continued migration
This commit is contained in:
@@ -1,258 +0,0 @@
|
||||
# tRPC Implementation Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This project implements a [tRPC](https://trpc.io/) API layer to provide type-safe communication between the frontend and backend. The implementation follows SolidStart's server-side rendering architecture with a clear separation of concerns.
|
||||
|
||||
## Architecture
|
||||
|
||||
The tRPC setup is organized in the following structure:
|
||||
|
||||
```
|
||||
src/
|
||||
├── server/
|
||||
│ └── api/
|
||||
│ ├── root.ts # Main router that combines all sub-routers
|
||||
│ ├── utils.ts # tRPC utility functions and initialization
|
||||
│ └── routers/ # Individual API route groups
|
||||
│ ├── auth.ts # Authentication procedures
|
||||
│ ├── database.ts # Database operations
|
||||
│ ├── example.ts # Example procedures
|
||||
│ ├── lineage.ts # Lineage-related APIs
|
||||
│ └── misc.ts # Miscellaneous endpoints
|
||||
└── routes/
|
||||
└── api/
|
||||
└── trpc/
|
||||
└── [trpc].ts # API endpoint handler
|
||||
```
|
||||
|
||||
## How to Use tRPC Procedures from the Frontend
|
||||
|
||||
The `api` client is pre-configured and available for use in components:
|
||||
|
||||
```typescript
|
||||
import { api } from "~/lib/api";
|
||||
|
||||
// Example usage in a component
|
||||
export function MyComponent() {
|
||||
const [result, setResult] = useState<string | null>(null);
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
// Call a tRPC procedure
|
||||
const data = await api.example.hello.query("World");
|
||||
setResult(data);
|
||||
} catch (error) {
|
||||
console.error("Error calling tRPC procedure:", error);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{result}</p>
|
||||
<button onClick={handleClick}>Call API</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## API Route Structure
|
||||
|
||||
### Root Router (`src/server/api/root.ts`)
|
||||
|
||||
The main router combines all individual routers:
|
||||
|
||||
```typescript
|
||||
export const appRouter = createTRPCRouter({
|
||||
example: exampleRouter,
|
||||
auth: authRouter,
|
||||
database: databaseRouter,
|
||||
lineage: lineageRouter,
|
||||
misc: miscRouter
|
||||
});
|
||||
```
|
||||
|
||||
### Procedure Types
|
||||
|
||||
tRPC provides two main procedure types:
|
||||
- **Query**: For read-only operations (GET requests)
|
||||
- **Mutation**: For write operations (POST, PUT, DELETE requests)
|
||||
|
||||
Example:
|
||||
|
||||
```typescript
|
||||
// Query procedure - read-only
|
||||
publicProcedure
|
||||
.input(z.string())
|
||||
.query(({ input }) => {
|
||||
return `Hello ${input}!`;
|
||||
})
|
||||
|
||||
// Mutation procedure - write operation
|
||||
publicProcedure
|
||||
.input(z.object({ name: z.string() }))
|
||||
.mutation(({ input }) => {
|
||||
// Logic for creating/updating data
|
||||
return { success: true, name: input.name };
|
||||
})
|
||||
```
|
||||
|
||||
## Adding New Endpoints
|
||||
|
||||
### 1. Create a new router file
|
||||
|
||||
Create a new file in `src/server/api/routers/`:
|
||||
|
||||
```typescript
|
||||
import { createTRPCRouter, publicProcedure } from "../utils";
|
||||
import { z } from "zod";
|
||||
|
||||
export const myRouter = createTRPCRouter({
|
||||
// Add your procedures here
|
||||
hello: publicProcedure
|
||||
.input(z.string())
|
||||
.query(({ input }) => {
|
||||
return `Hello ${input}!`;
|
||||
}),
|
||||
});
|
||||
```
|
||||
|
||||
### 2. Register the router in the root
|
||||
|
||||
Add your new router to `src/server/api/root.ts`:
|
||||
|
||||
```typescript
|
||||
import { exampleRouter } from "./routers/example";
|
||||
import { authRouter } from "./routers/auth";
|
||||
import { databaseRouter } from "./routers/database";
|
||||
import { lineageRouter } from "./routers/lineage";
|
||||
import { miscRouter } from "./routers/misc";
|
||||
import { myRouter } from "./routers/myRouter"; // Add this import
|
||||
import { createTRPCRouter } from "./utils";
|
||||
|
||||
export const appRouter = createTRPCRouter({
|
||||
example: exampleRouter,
|
||||
auth: authRouter,
|
||||
database: databaseRouter,
|
||||
lineage: lineageRouter,
|
||||
misc: miscRouter,
|
||||
myRouter: myRouter, // Add this line
|
||||
});
|
||||
```
|
||||
|
||||
### 3. Use in frontend
|
||||
|
||||
```typescript
|
||||
// In your frontend component
|
||||
const data = await api.myRouter.hello.query("World");
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Type Safety**: Always use Zod schemas to validate input data and return types.
|
||||
|
||||
2. **Error Handling**: Implement proper error handling with try/catch blocks in async procedures.
|
||||
|
||||
3. **Procedure Organization**: Group related procedures into logical routers.
|
||||
|
||||
4. **Consistent Naming**: Use clear, descriptive names for your procedures and routers.
|
||||
|
||||
5. **Documentation**: Document each procedure with clear descriptions of what it does.
|
||||
|
||||
## Example Usage Patterns
|
||||
|
||||
### Query Procedure (GET)
|
||||
```typescript
|
||||
// In your router file
|
||||
getPosts: publicProcedure
|
||||
.input(z.object({
|
||||
limit: z.number().optional(),
|
||||
offset: z.number().optional()
|
||||
}))
|
||||
.query(({ input }) => {
|
||||
// Return data from database or external service
|
||||
return { posts: [], total: 0 };
|
||||
})
|
||||
```
|
||||
|
||||
```typescript
|
||||
// In frontend component
|
||||
const { data, isLoading } = api.database.getPosts.useQuery({ limit: 10 });
|
||||
```
|
||||
|
||||
### Mutation Procedure (POST/PUT/DELETE)
|
||||
```typescript
|
||||
// In your router file
|
||||
createPost: publicProcedure
|
||||
.input(z.object({
|
||||
title: z.string(),
|
||||
content: z.string()
|
||||
}))
|
||||
.mutation(({ input }) => {
|
||||
// Create post in database
|
||||
return { success: true, post: { id: "1", ...input } };
|
||||
})
|
||||
```
|
||||
|
||||
```typescript
|
||||
// In frontend component
|
||||
const { mutateAsync } = api.database.createPost.useMutation();
|
||||
|
||||
const handleClick = async () => {
|
||||
try {
|
||||
const result = await mutateAsync({
|
||||
title: "New Post",
|
||||
content: "Post content"
|
||||
});
|
||||
console.log("Created post:", result);
|
||||
} catch (error) {
|
||||
console.error("Error creating post:", error);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Available Endpoints
|
||||
|
||||
### Auth
|
||||
- `auth.githubCallback` - GitHub OAuth callback
|
||||
- `auth.googleCallback` - Google OAuth callback
|
||||
- `auth.emailLogin` - Email login
|
||||
- `auth.emailVerification` - Email verification
|
||||
|
||||
### Database
|
||||
- `database.getCommentReactions` - Get comment reactions
|
||||
- `database.postCommentReaction` - Add comment reaction
|
||||
- `database.deleteCommentReaction` - Remove comment reaction
|
||||
- `database.getComments` - Get comments for a post
|
||||
- `database.getPosts` - Get posts with pagination
|
||||
- `database.createPost` - Create new post
|
||||
- `database.updatePost` - Update existing post
|
||||
- `database.deletePost` - Delete post
|
||||
- `database.getPostLikes` - Get likes for a post
|
||||
- `database.likePost` - Like a post
|
||||
- `database.unlikePost` - Unlike a post
|
||||
|
||||
### Lineage
|
||||
- `lineage.databaseManagement` - Database management operations
|
||||
- `lineage.analytics` - Analytics endpoints
|
||||
- `lineage.appleAuth` - Apple authentication
|
||||
- `lineage.emailLogin` - Email login
|
||||
- `lineage.emailRegister` - Email registration
|
||||
- `lineage.emailVerify` - Email verification
|
||||
- `lineage.googleRegister` - Google registration
|
||||
- `lineage.attacks` - Attack data
|
||||
- `lineage.conditions` - Condition data
|
||||
- `lineage.dungeons` - Dungeon data
|
||||
- `lineage.enemies` - Enemy data
|
||||
- `lineage.items` - Item data
|
||||
- `lineage.misc` - Miscellaneous data
|
||||
- `lineage.offlineSecret` - Offline secret endpoint
|
||||
- `lineage.pvpGet` - PvP GET operations
|
||||
- `lineage.pvpPost` - PvP POST operations
|
||||
- `lineage.tokens` - Token operations
|
||||
|
||||
### Misc
|
||||
- `misc.downloads` - Downloads endpoint
|
||||
- `misc.s3Delete` - Delete S3 object
|
||||
- `misc.s3Get` - Get S3 object
|
||||
- `misc.hashPassword` - Hash password
|
||||
15
package.json
15
package.json
@@ -7,18 +7,31 @@
|
||||
"start": "vinxi start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.953.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.953.0",
|
||||
"@libsql/client": "^0.15.15",
|
||||
"@solidjs/meta": "^0.29.4",
|
||||
"@solidjs/router": "^0.15.0",
|
||||
"@solidjs/start": "^1.1.0",
|
||||
"@tailwindcss/vite": "^4.0.7",
|
||||
"@trpc/client": "^10.45.2",
|
||||
"@trpc/server": "^10.45.2",
|
||||
"@tursodatabase/api": "^1.9.2",
|
||||
"@typeschema/valibot": "^0.13.4",
|
||||
"bcrypt": "^6.0.0",
|
||||
"google-auth-library": "^10.5.0",
|
||||
"jose": "^6.1.3",
|
||||
"solid-js": "^1.9.5",
|
||||
"uuid": "^13.0.0",
|
||||
"valibot": "^0.29.0",
|
||||
"vinxi": "^0.5.7"
|
||||
"vinxi": "^0.5.7",
|
||||
"zod": "^4.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bcrypt": "^6.0.0",
|
||||
"trpc-panel": "^1.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { v4 as uuidV4 } from "uuid";
|
||||
import { env } from "@/env.mjs";
|
||||
import { cookies } from "next/headers";
|
||||
import { User } from "@/types/model-types";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const params = request.nextUrl.searchParams;
|
||||
const code = params.get("code");
|
||||
if (code) {
|
||||
const tokenResponse = await fetch(
|
||||
"https://github.com/login/oauth/access_token",
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
client_id: env.NEXT_PUBLIC_GITHUB_CLIENT_ID,
|
||||
client_secret: env.GITHUB_CLIENT_SECRET,
|
||||
code,
|
||||
}),
|
||||
},
|
||||
);
|
||||
const { access_token } = await tokenResponse.json();
|
||||
|
||||
const userResponse = await fetch("https://api.github.com/user", {
|
||||
headers: {
|
||||
Authorization: `token ${access_token}`,
|
||||
},
|
||||
});
|
||||
|
||||
const user = await userResponse.json();
|
||||
const login = user.login;
|
||||
const conn = ConnectionFactory();
|
||||
|
||||
const query = `SELECT * FROM User WHERE provider = ? AND display_name = ?`;
|
||||
const params = ["github", login];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
if (res.rows[0]) {
|
||||
const token = jwt.sign(
|
||||
{ id: (res.rows[0] as unknown as User).id },
|
||||
env.JWT_SECRET_KEY,
|
||||
{
|
||||
expiresIn: 60 * 60 * 24 * 14, // expires in 14 days
|
||||
},
|
||||
);
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
} else {
|
||||
const icon = user.avatar_url;
|
||||
const email = user.email;
|
||||
const userId = uuidV4();
|
||||
|
||||
const insertQuery = `INSERT INTO User (id, email, display_name, provider, image) VALUES (?, ?, ?, ?, ?)`;
|
||||
const insertParams = [userId, email, login, "github", icon];
|
||||
await conn.execute({ sql: insertQuery, args: insertParams });
|
||||
const token = jwt.sign({ id: userId }, env.JWT_SECRET_KEY, {
|
||||
expiresIn: 60 * 60 * 24 * 14, // expires in 14 days
|
||||
});
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.redirect(`${env.NEXT_PUBLIC_DOMAIN}/account`);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `authentication failed: no code on callback`,
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { v4 as uuidV4 } from "uuid";
|
||||
import { env } from "@/env.mjs";
|
||||
import { cookies } from "next/headers";
|
||||
import { User } from "@/types/model-types";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const params = request.nextUrl.searchParams;
|
||||
const code = params.get("code");
|
||||
if (code) {
|
||||
const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
},
|
||||
body: new URLSearchParams({
|
||||
code: code,
|
||||
client_id: env.NEXT_PUBLIC_GOOGLE_CLIENT_ID,
|
||||
client_secret: env.GOOGLE_CLIENT_SECRET,
|
||||
redirect_uri: "https://www.freno.me/api/auth/callback/google",
|
||||
grant_type: "authorization_code",
|
||||
}),
|
||||
});
|
||||
|
||||
const { access_token } = await tokenResponse.json();
|
||||
|
||||
const userResponse = await fetch(
|
||||
"https://www.googleapis.com/oauth2/v3/userinfo",
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${access_token}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const userData = await userResponse.json();
|
||||
console.log(userData);
|
||||
const name = userData.name;
|
||||
const image = userData.picture;
|
||||
const email = userData.email;
|
||||
const email_verified = userData.email_verified;
|
||||
|
||||
const conn = ConnectionFactory();
|
||||
|
||||
const query = `SELECT * FROM User WHERE provider = ? AND email = ?`;
|
||||
const params = ["google", email];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
if (res.rows[0]) {
|
||||
const token = jwt.sign(
|
||||
{ id: (res.rows[0] as unknown as User).id },
|
||||
env.JWT_SECRET_KEY,
|
||||
{
|
||||
expiresIn: 60 * 60 * 24 * 14, // expires in 14 days
|
||||
},
|
||||
);
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
} else {
|
||||
const userId = uuidV4();
|
||||
|
||||
const insertQuery = `INSERT INTO User (id, email, email_verified, display_name, provider, image) VALUES (?, ?, ?, ?, ?, ?)`;
|
||||
const insertParams = [
|
||||
userId,
|
||||
email,
|
||||
email_verified,
|
||||
name,
|
||||
"google",
|
||||
image,
|
||||
];
|
||||
await conn.execute({
|
||||
sql: insertQuery,
|
||||
args: insertParams,
|
||||
});
|
||||
const token = jwt.sign({ id: userId }, env.JWT_SECRET_KEY, {
|
||||
expiresIn: 60 * 60 * 24 * 14, // expires in 14 days
|
||||
});
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
}
|
||||
|
||||
return NextResponse.redirect(`${env.NEXT_PUBLIC_DOMAIN}/account`);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `authentication failed: no code on callback`,
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { JwtPayload } from "jsonwebtoken";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { env } from "@/env.mjs";
|
||||
import { cookies } from "next/headers";
|
||||
import { User } from "@/types/model-types";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ email: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const secretKey = env.JWT_SECRET_KEY;
|
||||
const params = request.nextUrl.searchParams;
|
||||
const token = params.get("token");
|
||||
const userEmail = readyParams.email;
|
||||
try {
|
||||
if (token) {
|
||||
const decoded = jwt.verify(token, secretKey) as JwtPayload;
|
||||
if (decoded.email == userEmail) {
|
||||
const conn = ConnectionFactory();
|
||||
const query = `SELECT * FROM User WHERE email = ?`;
|
||||
const params = [decoded.email];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
const token = jwt.sign(
|
||||
{ id: (res.rows[0] as unknown as User).id },
|
||||
env.JWT_SECRET_KEY,
|
||||
{
|
||||
expiresIn: 60 * 60 * 24 * 14, // expires in 14 days
|
||||
},
|
||||
);
|
||||
if (decoded.rememberMe) {
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
maxAge: 60 * 60 * 24 * 14,
|
||||
});
|
||||
} else {
|
||||
(await cookies()).set({
|
||||
name: "userIDToken",
|
||||
value: token,
|
||||
});
|
||||
}
|
||||
return NextResponse.redirect(`${env.NEXT_PUBLIC_DOMAIN}/account`);
|
||||
}
|
||||
}
|
||||
return NextResponse.json(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `authentication failed: no token`,
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `authentication failed: ${err}`,
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
import { env } from "@/env.mjs";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ email: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const secretKey = env.JWT_SECRET_KEY;
|
||||
const params = request.nextUrl.searchParams;
|
||||
const token = params.get("token");
|
||||
const userEmail = readyParams.email;
|
||||
try {
|
||||
if (token) {
|
||||
const decoded = jwt.verify(token, secretKey) as JwtPayload;
|
||||
if (decoded.email == userEmail) {
|
||||
const conn = ConnectionFactory();
|
||||
const query = `UPDATE User SET email_verified = ? WHERE email = ?`;
|
||||
const params = [true, userEmail];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "email verification success, you may close this window",
|
||||
}),
|
||||
{ status: 202, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
return NextResponse.json(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: `authentication failed: no token`,
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Invalid token:", err);
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "authentication failed: Invalid token",
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: { params: Promise<{ commentID: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const commentID = readyParams.commentID;
|
||||
const conn = ConnectionFactory();
|
||||
const commentQuery = "SELECT * FROM CommentReaction WHERE comment_id = ?";
|
||||
const commentParams = [commentID];
|
||||
const commentResults = await conn.execute({
|
||||
sql: commentQuery,
|
||||
args: commentParams,
|
||||
});
|
||||
return NextResponse.json(
|
||||
{ commentReactions: commentResults.rows },
|
||||
{ status: 202 },
|
||||
);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { CommentReactionInput } from "@/types/input-types";
|
||||
import { CommentReaction } from "@/types/model-types";
|
||||
|
||||
export async function POST(
|
||||
input: NextRequest,
|
||||
context: { params: Promise<{ type: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const inputData = (await input.json()) as CommentReactionInput;
|
||||
const { comment_id, user_id } = inputData;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `
|
||||
INSERT INTO CommentReaction (type, comment_id, user_id)
|
||||
VALUES (?, ?, ?)
|
||||
`;
|
||||
const params = [readyParams.type, comment_id, user_id];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
const followUpQuery = `SELECT * FROM CommentReaction WHERE comment_id = ?`;
|
||||
const followUpParams = [comment_id];
|
||||
const res = await conn.execute({ sql: followUpQuery, args: followUpParams });
|
||||
const data = (res.rows as unknown as CommentReaction[]).filter(
|
||||
(commentReaction) => commentReaction.comment_id == comment_id,
|
||||
);
|
||||
return NextResponse.json({ commentReactions: data || [] });
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { CommentReactionInput } from "@/types/input-types";
|
||||
import { CommentReaction } from "@/types/model-types";
|
||||
|
||||
export async function POST(
|
||||
input: NextRequest,
|
||||
context: { params: Promise<{ type: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const inputData = (await input.json()) as CommentReactionInput;
|
||||
const { comment_id, user_id } = inputData;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `
|
||||
DELETE FROM CommentReaction
|
||||
WHERE type = ? AND comment_id = ? AND user_id = ?
|
||||
`;
|
||||
const params = [readyParams.type, comment_id, user_id];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
|
||||
const followUpQuery = `SELECT * FROM CommentReaction WHERE comment_id = ?`;
|
||||
const followUpParams = [comment_id];
|
||||
const res = await conn.execute({ sql: followUpQuery, args: followUpParams });
|
||||
const data = (res.rows as unknown as CommentReaction[]).filter(
|
||||
(commentReaction) => commentReaction.comment_id == comment_id,
|
||||
);
|
||||
return NextResponse.json({ commentReactions: data || [] });
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: {
|
||||
params: Promise<{ post_id: string }>;
|
||||
},
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `SELECT * FROM Comment WHERE post_id = ?`;
|
||||
const params = [readyParams.post_id];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
return NextResponse.json({ comments: res.rows }, { status: 302 });
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET() {
|
||||
const conn = ConnectionFactory();
|
||||
const query = `SELECT * FROM Comment`;
|
||||
const res = await conn.execute(query);
|
||||
return NextResponse.json({ comments: res.rows });
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { PostLikeInput } from "@/types/input-types";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as PostLikeInput;
|
||||
const { user_id, post_id } = inputData;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `INSERT INTO PostLike (user_id, post_id)
|
||||
VALUES (?, ?)`;
|
||||
const params = [user_id, post_id];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
const followUpQuery = `SELECT * FROM PostLike WHERE post_id = ?`;
|
||||
const followUpParams = [post_id];
|
||||
const res = await conn.execute({ sql: followUpQuery, args: followUpParams });
|
||||
return NextResponse.json({ newLikes: res.rows });
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { PostLikeInput } from "@/types/input-types";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as PostLikeInput;
|
||||
const { user_id, post_id } = inputData;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `
|
||||
DELETE FROM PostLike
|
||||
WHERE user_id = ? AND post_id = ?
|
||||
`;
|
||||
const params = [user_id, post_id];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
const followUpQuery = `SELECT * FROM PostLike WHERE post_id=?`;
|
||||
const followUpParams = [post_id];
|
||||
const res = await conn.execute({ sql: followUpQuery, args: followUpParams });
|
||||
return NextResponse.json({ newLikes: res.rows });
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function GET(
|
||||
_: NextRequest,
|
||||
context: { params: Promise<{ category: string; id: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
if (readyParams.category !== "blog" && readyParams.category !== "project") {
|
||||
return NextResponse.json(
|
||||
{ error: "invalid category value" },
|
||||
{ status: 400 },
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
const conn = ConnectionFactory();
|
||||
const query = `SELECT * FROM Post WHERE id = ?`;
|
||||
const params = [parseInt(readyParams.id)];
|
||||
const results = await conn.execute({ sql: query, args: params });
|
||||
const tagQuery = `SELECT * FROM Tag WHERE post_id = ?`;
|
||||
const tagRes = await conn.execute({ sql: tagQuery, args: params });
|
||||
if (results.rows[0]) {
|
||||
return NextResponse.json(
|
||||
{
|
||||
post: results.rows[0],
|
||||
tags: tagRes.rows,
|
||||
},
|
||||
{ status: 200 },
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(
|
||||
{
|
||||
post: [],
|
||||
},
|
||||
{ status: 204 },
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { env } from "@/env.mjs";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { Post } from "@/types/model-types";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ category: string; title: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
if (readyParams.category !== "blog" && readyParams.category !== "project") {
|
||||
return NextResponse.json(
|
||||
{ error: "invalid category value" },
|
||||
{ status: 400 },
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
let privilegeLevel = "anonymous";
|
||||
const token = request.cookies.get("userIDToken");
|
||||
if (token) {
|
||||
if (token.value == env.ADMIN_ID) {
|
||||
privilegeLevel = "admin";
|
||||
} else {
|
||||
privilegeLevel = "user";
|
||||
}
|
||||
}
|
||||
const conn = ConnectionFactory();
|
||||
|
||||
const projectQuery =
|
||||
"SELECT p.*, c.*, l.*,t.* FROM Post p JOIN Comment c ON p.id = c.post_id JOIN PostLike l ON p.id = l.post_idJOIN Tag t ON p.id = t.post_id WHERE p.title = ? AND p.category = ? AND p.published = ?;";
|
||||
const projectParams = [readyParams.title, readyParams.category, true];
|
||||
const projectResults = await conn.execute({
|
||||
sql: projectQuery,
|
||||
args: projectParams,
|
||||
});
|
||||
if (projectResults.rows[0]) {
|
||||
const post_id = (projectResults.rows[0] as unknown as Post).id;
|
||||
|
||||
const commentQuery = "SELECT * FROM Comment WHERE post_id = ?";
|
||||
const commentResults = await conn.execute({
|
||||
sql: commentQuery,
|
||||
args: [post_id],
|
||||
});
|
||||
|
||||
const likeQuery = "SELECT * FROM PostLike WHERE post_id = ?";
|
||||
const likeQueryResults = await conn.execute({
|
||||
sql: likeQuery,
|
||||
args: [post_id],
|
||||
});
|
||||
|
||||
const tagsQuery = "SELECT * FROM Tag WHERE post_id = ?";
|
||||
const tagResults = await conn.execute({
|
||||
sql: tagsQuery,
|
||||
args: [post_id],
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
{
|
||||
project: projectResults.rows[0],
|
||||
comments: commentResults.rows,
|
||||
likes: likeQueryResults.rows,
|
||||
tagResults: tagResults.rows,
|
||||
privilegeLevel: privilegeLevel,
|
||||
},
|
||||
{ status: 200 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json({ status: 200 });
|
||||
} catch (e) {
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { env } from "@/env.mjs";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
interface POSTInputData {
|
||||
title: string;
|
||||
subtitle: string | null;
|
||||
body: string | null;
|
||||
banner_photo: string | null;
|
||||
published: boolean;
|
||||
tags: string[] | null;
|
||||
}
|
||||
|
||||
interface PATCHInputData {
|
||||
id: number;
|
||||
title: string | null;
|
||||
subtitle: string | null;
|
||||
body: string | null;
|
||||
banner_photo: string | null;
|
||||
published: boolean | null;
|
||||
tags: string[] | null;
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
input: NextRequest,
|
||||
context: { params: Promise<{ category: string }> },
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
if (readyParams.category !== "blog" && readyParams.category !== "project") {
|
||||
return NextResponse.json(
|
||||
{ error: "invalid category value" },
|
||||
{ status: 400 },
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
const inputData = (await input.json()) as POSTInputData;
|
||||
const { title, subtitle, body, banner_photo, published, tags } =
|
||||
inputData;
|
||||
const userIDCookie = (await cookies()).get("userIDToken");
|
||||
const fullURL = env.NEXT_PUBLIC_AWS_BUCKET_STRING + banner_photo;
|
||||
|
||||
if (userIDCookie) {
|
||||
const author_id = userIDCookie.value;
|
||||
const conn = ConnectionFactory();
|
||||
const query = `
|
||||
INSERT INTO Post (title, category, subtitle, body, banner_photo, published, author_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
const params = [
|
||||
title,
|
||||
readyParams.category,
|
||||
subtitle,
|
||||
body,
|
||||
banner_photo ? fullURL : null,
|
||||
published,
|
||||
author_id,
|
||||
];
|
||||
const results = await conn.execute({ sql: query, args: params });
|
||||
if (tags) {
|
||||
let query = "INSERT INTO Tag (value, post_id) VALUES ";
|
||||
let values = tags.map(
|
||||
(tag) => `("${tag}", ${results.lastInsertRowid})`,
|
||||
);
|
||||
query += values.join(", ");
|
||||
await conn.execute(query);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ data: results.lastInsertRowid },
|
||||
{ status: 201 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json({ error: "no cookie" }, { status: 401 });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
}
|
||||
export async function PATCH(input: NextRequest) {
|
||||
try {
|
||||
const inputData = (await input.json()) as PATCHInputData;
|
||||
|
||||
const conn = ConnectionFactory();
|
||||
const { query, params } = await createUpdateQuery(inputData);
|
||||
const results = await conn.execute({
|
||||
sql: query,
|
||||
args: params as string[],
|
||||
});
|
||||
const { tags, id } = inputData;
|
||||
const deleteTagsQuery = `DELETE FROM Tag WHERE post_id = ?`;
|
||||
await conn.execute({ sql: deleteTagsQuery, args: [id.toString()] });
|
||||
if (tags) {
|
||||
let query = "INSERT INTO Tag (value, post_id) VALUES ";
|
||||
let values = tags.map((tag) => `("${tag}", ${id})`);
|
||||
query += values.join(", ");
|
||||
await conn.execute(query);
|
||||
}
|
||||
return NextResponse.json(
|
||||
{ data: results.lastInsertRowid },
|
||||
{ status: 201 },
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
|
||||
async function createUpdateQuery(data: PATCHInputData) {
|
||||
const { id, title, subtitle, body, banner_photo, published } = data;
|
||||
|
||||
let query = "UPDATE Post SET ";
|
||||
let params = [];
|
||||
let first = true;
|
||||
|
||||
if (title !== null) {
|
||||
query += first ? "title = ?" : ", title = ?";
|
||||
params.push(title);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (subtitle !== null) {
|
||||
query += first ? "subtitle = ?" : ", subtitle = ?";
|
||||
params.push(subtitle);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (body !== null) {
|
||||
query += first ? "body = ?" : ", body = ?";
|
||||
params.push(body);
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (banner_photo !== null) {
|
||||
query += first ? "banner_photo = ?" : ", banner_photo = ?";
|
||||
if (banner_photo == "_DELETE_IMAGE_") {
|
||||
params.push(undefined);
|
||||
} else {
|
||||
params.push(env.NEXT_PUBLIC_AWS_BUCKET_STRING + banner_photo);
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (published !== null) {
|
||||
query += first ? "published = ?" : ", published = ?";
|
||||
params.push(published);
|
||||
first = false;
|
||||
}
|
||||
|
||||
query += first ? "author_id = ?" : ", author_id = ?";
|
||||
params.push((await cookies()).get("userIDToken")?.value);
|
||||
|
||||
query += " WHERE id = ?";
|
||||
params.push(id);
|
||||
|
||||
return { query, params };
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { cookies } from "next/headers";
|
||||
import { newEmailInput } from "@/types/input-types";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as newEmailInput;
|
||||
const { id, newEmail } = inputData;
|
||||
const oldEmail = (await cookies()).get("emailToken");
|
||||
const conn = ConnectionFactory();
|
||||
const query = `UPDATE User SET email = ? WHERE id = ? AND email = ?`;
|
||||
const params = [newEmail, id, oldEmail];
|
||||
try {
|
||||
const res = await conn.execute({ sql: query, args: params as string[] });
|
||||
return NextResponse.json({ res: res }, { status: 202 });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return NextResponse.json({ status: 400 });
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { User } from "@/types/model-types";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { NextResponse } from "next/server";
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
try {
|
||||
const conn = ConnectionFactory();
|
||||
const userQuery = "SELECT * FROM User WHERE id =?";
|
||||
const params = await context.params;
|
||||
const userParams = [params.id];
|
||||
const res = await conn.execute({ sql: userQuery, args: userParams });
|
||||
if (res.rows[0]) {
|
||||
const user = res.rows[0] as unknown as User;
|
||||
if (user && user.display_name !== "user deleted")
|
||||
return NextResponse.json(
|
||||
{
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
emailVerified: user.email_verified,
|
||||
image: user.image,
|
||||
displayName: user.display_name,
|
||||
provider: user.provider,
|
||||
hasPassword: !!user.password_hash,
|
||||
},
|
||||
{ status: 202 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json({}, { status: 200 });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return NextResponse.json({}, { status: 200 });
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
import { changeImageInput } from "@/types/input-types";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
const conn = ConnectionFactory();
|
||||
const query = "SELECT * FROM User WHERE id = ?";
|
||||
const params = await context.params;
|
||||
const idArr = [params.id];
|
||||
const results = await conn.execute({ sql: query, args: idArr });
|
||||
return NextResponse.json({ user: results.rows[0] }, { status: 200 });
|
||||
}
|
||||
export async function POST(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
const inputData = (await request.json()) as changeImageInput;
|
||||
const { imageURL } = inputData;
|
||||
try {
|
||||
const conn = ConnectionFactory();
|
||||
const query = `UPDATE User SET image = ? WHERE id = ?`;
|
||||
const fullURL = env.NEXT_PUBLIC_AWS_BUCKET_STRING + imageURL;
|
||||
const params = [imageURL ? fullURL : null, (await context.params).id];
|
||||
await conn.execute({ sql: query, args: params });
|
||||
return NextResponse.json({ res: "success" }, { status: 200 });
|
||||
} catch (err) {
|
||||
return NextResponse.json({ res: err }, { status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { User } from "@/types/model-types";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { NextResponse } from "next/server";
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: { params: Promise<{ id: string }> },
|
||||
) {
|
||||
try {
|
||||
const conn = ConnectionFactory();
|
||||
const userQuery = "SELECT email, display_name, image FROM User WHERE id =?";
|
||||
const params = await context.params;
|
||||
const userParams = [params.id];
|
||||
const res = await conn.execute({ sql: userQuery, args: userParams });
|
||||
if (res.rows[0]) {
|
||||
const user = res.rows[0] as unknown as User;
|
||||
if (user && user.display_name !== "user deleted")
|
||||
return NextResponse.json(
|
||||
{
|
||||
email: user.email,
|
||||
image: user.image,
|
||||
display_name: user.display_name,
|
||||
},
|
||||
{ status: 202 },
|
||||
);
|
||||
}
|
||||
return NextResponse.json({}, { status: 200 });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return NextResponse.json({}, { status: 200 });
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
const assets: Record<string, string> = {
|
||||
"shapes-with-abigail": "shapes-with-abigail.apk",
|
||||
"magic-delve": "magic-delve.apk",
|
||||
cork: "Cork.zip",
|
||||
};
|
||||
|
||||
const bucket = "frenomedownloads";
|
||||
|
||||
export async function GET(
|
||||
_: Request,
|
||||
context: {
|
||||
params: Promise<{ asset_name: string }>;
|
||||
},
|
||||
) {
|
||||
const readyParams = await context.params;
|
||||
const params = {
|
||||
Bucket: bucket,
|
||||
Key: assets[readyParams.asset_name],
|
||||
Expires: 60 * 60,
|
||||
};
|
||||
const credentials = {
|
||||
accessKeyId: env._AWS_ACCESS_KEY,
|
||||
secretAccessKey: env._AWS_SECRET_KEY,
|
||||
};
|
||||
try {
|
||||
const client = new S3Client({
|
||||
region: env.AWS_REGION,
|
||||
credentials: credentials,
|
||||
});
|
||||
|
||||
const command = new GetObjectCommand(params);
|
||||
const signedUrl = await getSignedUrl(client, command, { expiresIn: 120 });
|
||||
return NextResponse.json({ downloadURL: signedUrl });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
const IGNORE = ["frenome", "magic-delve-conductor"];
|
||||
|
||||
export async function GET() {
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT database_url FROM User WHERE database_url IS NOT NULL";
|
||||
try {
|
||||
const res = await conn.execute(query);
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
const linkedDatabaseUrls = res.rows.map((row) => row.database_url);
|
||||
|
||||
const all_dbs = await turso.databases.list();
|
||||
console.log(all_dbs);
|
||||
const dbs_to_delete = all_dbs.filter((db) => {
|
||||
return !IGNORE.includes(db.name) && !linkedDatabaseUrls.includes(db.name);
|
||||
});
|
||||
//console.log("will delete:", dbs_to_delete);
|
||||
} catch (e) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: e,
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
}),
|
||||
{ status: 200, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
const conn = LineageConnectionFactory();
|
||||
const query =
|
||||
"SELECT * FROM User WHERE datetime(db_destroy_date) < datetime('now');";
|
||||
try {
|
||||
const res = await conn.execute(query);
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
|
||||
res.rows.forEach(async (row) => {
|
||||
const db_url = row.database_url;
|
||||
|
||||
await turso.databases.delete(db_url as string);
|
||||
const query =
|
||||
"UPDATE User SET database_url = ?, database_token = ?, db_destroy_date = ? WHERE id = ?";
|
||||
const params = [null, null, null, row.id];
|
||||
conn.execute({ sql: query, args: params });
|
||||
});
|
||||
} catch (e) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: e,
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
}),
|
||||
{ status: 200, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const {
|
||||
playerID,
|
||||
dungeonProgression,
|
||||
playerClass,
|
||||
spellCount,
|
||||
proficiencies,
|
||||
jobs,
|
||||
resistanceTable,
|
||||
damageTable,
|
||||
} = await req.json();
|
||||
const conn = LineageConnectionFactory();
|
||||
try {
|
||||
const res = await conn.execute({
|
||||
sql: `
|
||||
INSERT OR REPLACE INTO Analytics
|
||||
(playerID, dungeonProgression, playerClass, spellCount, proficiencies, jobs, resistanceTable, damageTable)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`,
|
||||
args: [
|
||||
playerID,
|
||||
JSON.stringify(dungeonProgression),
|
||||
playerClass,
|
||||
spellCount,
|
||||
JSON.stringify(proficiencies),
|
||||
JSON.stringify(jobs),
|
||||
JSON.stringify(resistanceTable),
|
||||
JSON.stringify(damageTable),
|
||||
],
|
||||
});
|
||||
console.log(res);
|
||||
|
||||
return NextResponse.json({ status: 200 });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
||||
return NextResponse.json({ status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { userString } = await req.json();
|
||||
if (!userString) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required fields",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT * FROM User WHERE apple_user_string = ?";
|
||||
const res = await conn.execute({ sql: query, args: [userString] });
|
||||
if (res.rows.length > 0) {
|
||||
return NextResponse.json(
|
||||
{ success: true, email: res.rows[0].email },
|
||||
{ status: 200 },
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json({ success: false }, { status: 404 });
|
||||
}
|
||||
}
|
||||
@@ -1,134 +0,0 @@
|
||||
import { LineageConnectionFactory, LineageDBInit } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const { email, userString } = await request.json();
|
||||
if (!userString) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required fields",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
let dbName;
|
||||
let dbToken;
|
||||
const conn = LineageConnectionFactory();
|
||||
|
||||
try {
|
||||
let checkUserQuery = "SELECT * FROM User WHERE apple_user_string = ?";
|
||||
|
||||
let args = [userString];
|
||||
if (email) {
|
||||
args.push(email);
|
||||
checkUserQuery += " OR email = ?";
|
||||
}
|
||||
const checkUserResult = await conn.execute({
|
||||
sql: checkUserQuery,
|
||||
args: args,
|
||||
});
|
||||
|
||||
if (checkUserResult.rows.length > 0) {
|
||||
const setClauses = [];
|
||||
const values = [];
|
||||
|
||||
if (email) {
|
||||
setClauses.push("email = ?");
|
||||
values.push(email);
|
||||
}
|
||||
setClauses.push("provider = ?", "apple_user_string = ?");
|
||||
values.push("apple", userString);
|
||||
const whereClause = `WHERE apple_user_string = ?${
|
||||
email && " OR email = ?"
|
||||
}`;
|
||||
values.push(userString);
|
||||
if (email) {
|
||||
values.push(email);
|
||||
}
|
||||
|
||||
const updateQuery = `UPDATE User SET ${setClauses.join(
|
||||
", ",
|
||||
)} ${whereClause}`;
|
||||
const updateRes = await conn.execute({
|
||||
sql: updateQuery,
|
||||
args: values,
|
||||
});
|
||||
if (updateRes.rowsAffected != 0) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "User information updated",
|
||||
email: checkUserResult.rows[0].email,
|
||||
}),
|
||||
{ status: 200, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} else {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "User update failed!",
|
||||
}),
|
||||
{ status: 418, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// User doesn't exist, insert new user and init database
|
||||
const dbInit = await LineageDBInit();
|
||||
dbToken = dbInit.token;
|
||||
dbName = dbInit.dbName;
|
||||
|
||||
try {
|
||||
const insertQuery = `
|
||||
INSERT INTO User (email, email_verified, apple_user_string, provider, database_name, database_token)
|
||||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
await conn.execute({
|
||||
sql: insertQuery,
|
||||
args: [email, true, userString, "apple", dbName, dbToken],
|
||||
});
|
||||
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "New user created",
|
||||
dbName,
|
||||
dbToken,
|
||||
}),
|
||||
{ status: 201, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} catch (error) {
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
await turso.databases.delete(dbName);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
if (dbName) {
|
||||
try {
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
await turso.databases.delete(dbName);
|
||||
} catch (deleteErr) {
|
||||
console.error("Error deleting database:", deleteErr);
|
||||
}
|
||||
}
|
||||
console.error("Error in Apple Sign-Up handler:", error);
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "An error occurred while processing the request",
|
||||
}),
|
||||
{ status: 500, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
import { env } from "@/env.mjs";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { OAuth2Client } from "google-auth-library";
|
||||
const CLIENT_ID = env.NEXT_PUBLIC_GOOGLE_CLIENT_ID_MAGIC_DELVE;
|
||||
|
||||
const client = new OAuth2Client(CLIENT_ID);
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return new NextResponse(JSON.stringify({ valid: false }), { status: 401 });
|
||||
}
|
||||
const { email, provider } = await req.json();
|
||||
if (!email) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ success: false, message: "missing email in body" }),
|
||||
{
|
||||
status: 401,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const token = authHeader.split(" ")[1];
|
||||
|
||||
try {
|
||||
let valid_request = false;
|
||||
if (provider == "email") {
|
||||
const decoded = jwt.verify(token, env.JWT_SECRET_KEY) as jwt.JwtPayload;
|
||||
if (decoded.email == email) {
|
||||
valid_request = true;
|
||||
}
|
||||
} else if (provider == "google") {
|
||||
const ticket = await client.verifyIdToken({
|
||||
idToken: token,
|
||||
audience: CLIENT_ID,
|
||||
});
|
||||
if (ticket.getPayload()?.email == email) {
|
||||
valid_request = true;
|
||||
}
|
||||
} else {
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT * FROM User WHERE apple_user_string = ?";
|
||||
const res = await conn.execute({ sql: query, args: [token] });
|
||||
if (res.rows.length > 0 && res.rows[0].email == email) {
|
||||
valid_request = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (valid_request) {
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT * FROM User WHERE email = ? LIMIT 1";
|
||||
const params = [email];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
if (res.rows.length === 1) {
|
||||
const user = res.rows[0];
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
db_name: user.database_name,
|
||||
db_token: user.database_token,
|
||||
}),
|
||||
{ status: 200 },
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({ success: false, message: "no user found" }),
|
||||
{
|
||||
status: 404,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ success: false, message: "destroy token" }),
|
||||
{
|
||||
status: 401,
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ success: false, message: error }),
|
||||
{
|
||||
status: 401,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import { LineageConnectionFactory, validateLineageRequest } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return NextResponse.json({
|
||||
status: 401,
|
||||
ok: false,
|
||||
message: "Missing or invalid authorization header.",
|
||||
});
|
||||
}
|
||||
const auth_token = authHeader.split(" ")[1];
|
||||
|
||||
const { email } = await req.json();
|
||||
if (!email) {
|
||||
return NextResponse.json({
|
||||
status: 400,
|
||||
ok: false,
|
||||
message: "Email is required to cancel the cron job.",
|
||||
});
|
||||
}
|
||||
|
||||
const conn = LineageConnectionFactory();
|
||||
|
||||
const resUser = await conn.execute({
|
||||
sql: `SELECT * FROM User WHERE email = ?;`,
|
||||
args: [email],
|
||||
});
|
||||
if (resUser.rows.length === 0) {
|
||||
return NextResponse.json({
|
||||
status: 404,
|
||||
ok: false,
|
||||
message: "User not found.",
|
||||
});
|
||||
}
|
||||
const userRow = resUser.rows[0];
|
||||
if (!userRow) {
|
||||
return NextResponse.json({ status: 404, ok: false });
|
||||
}
|
||||
|
||||
const valid = await validateLineageRequest({ auth_token, userRow });
|
||||
if (!valid) {
|
||||
return NextResponse.json({
|
||||
status: 401,
|
||||
ok: false,
|
||||
message: "Invalid credentials for cancelation.",
|
||||
});
|
||||
}
|
||||
|
||||
const result = await conn.execute({
|
||||
sql: `DELETE FROM cron WHERE email = ?;`,
|
||||
args: [email],
|
||||
});
|
||||
|
||||
if (result.rowsAffected > 0) {
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
ok: true,
|
||||
message: "Cron job(s) canceled successfully.",
|
||||
});
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
status: 404,
|
||||
ok: false,
|
||||
message: "No cron job found for the given email.",
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { email } = await req.json();
|
||||
const conn = LineageConnectionFactory();
|
||||
try {
|
||||
const res = await conn.execute({
|
||||
sql: `SELECT * FROM cron WHERE email = ?`,
|
||||
args: [email],
|
||||
});
|
||||
const cronRow = res.rows[0];
|
||||
if (!cronRow) {
|
||||
return NextResponse.json({ status: 204, ok: true });
|
||||
}
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 200,
|
||||
created_at: cronRow.created_at,
|
||||
});
|
||||
} catch (e) {
|
||||
return NextResponse.json({ status: 500, ok: false });
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import { dumpAndSendDB, LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
export async function GET() {
|
||||
const conn = LineageConnectionFactory();
|
||||
const res = await conn.execute(
|
||||
`SELECT * FROM cron WHERE created_at <= datetime('now', '-1 day');`,
|
||||
);
|
||||
|
||||
if (res.rows.length > 0) {
|
||||
const executed_ids = [];
|
||||
for (const row of res.rows) {
|
||||
const { id, db_name, db_token, send_dump_target, email } = row;
|
||||
|
||||
if (send_dump_target) {
|
||||
const res = await dumpAndSendDB({
|
||||
dbName: db_name as string,
|
||||
dbToken: db_token as string,
|
||||
sendTarget: send_dump_target as string,
|
||||
});
|
||||
if (res.success) {
|
||||
//const res = await turso.databases.delete(db_name as string);
|
||||
//
|
||||
const res = await fetch(
|
||||
`https://api.turso.tech/v1/organizations/mikefreno/databases/${db_name}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${env.TURSO_DB_API_TOKEN}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (res.ok) {
|
||||
executed_ids.push(id);
|
||||
// Shouldn't fail. No idea what the response from turso would be at this point - not documented
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const res = await fetch(
|
||||
`https://api.turso.tech/v1/organizations/mikefreno/databases/${db_name}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${env.TURSO_DB_API_TOKEN}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (res.ok) {
|
||||
conn.execute({
|
||||
sql: `DELETE FROM User WHERE email = ?`,
|
||||
args: [email],
|
||||
});
|
||||
executed_ids.push(id);
|
||||
// Shouldn't fail. No idea what the response from turso would be at this point - not documented
|
||||
}
|
||||
}
|
||||
}
|
||||
if (executed_ids.length > 0) {
|
||||
const placeholders = executed_ids.map(() => "?").join(", ");
|
||||
const deleteQuery = `DELETE FROM cron WHERE id IN (${placeholders});`;
|
||||
await conn.execute({ sql: deleteQuery, args: executed_ids });
|
||||
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
message:
|
||||
"Processed databases deleted and corresponding cron rows removed.",
|
||||
});
|
||||
}
|
||||
}
|
||||
return NextResponse.json({ status: 200, ok: true });
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import {
|
||||
dumpAndSendDB,
|
||||
LineageConnectionFactory,
|
||||
validateLineageRequest,
|
||||
} from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return NextResponse.json({ status: 401, ok: false });
|
||||
}
|
||||
|
||||
const auth_token = authHeader.split(" ")[1];
|
||||
const { email, db_name, db_token, skip_cron, send_dump_target } =
|
||||
await req.json();
|
||||
if (!email || !db_name || !db_token || !auth_token) {
|
||||
return NextResponse.json({
|
||||
status: 401,
|
||||
message: "Missing required fields",
|
||||
});
|
||||
}
|
||||
|
||||
const conn = LineageConnectionFactory();
|
||||
const res = await conn.execute({
|
||||
sql: `SELECT * FROM User WHERE email = ?`,
|
||||
args: [email],
|
||||
});
|
||||
const userRow = res.rows[0];
|
||||
if (!userRow) {
|
||||
return NextResponse.json({ status: 404, ok: false });
|
||||
}
|
||||
|
||||
const valid = await validateLineageRequest({ auth_token, userRow });
|
||||
if (!valid) {
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 401,
|
||||
message: "Invalid Verification",
|
||||
});
|
||||
}
|
||||
|
||||
const { database_token, database_name } = userRow;
|
||||
|
||||
if (database_token !== db_token || database_name !== db_name) {
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 401,
|
||||
message: "Incorrect Verification",
|
||||
});
|
||||
}
|
||||
|
||||
if (skip_cron) {
|
||||
if (send_dump_target) {
|
||||
const res = await dumpAndSendDB({
|
||||
dbName: db_name,
|
||||
dbToken: db_token,
|
||||
sendTarget: send_dump_target,
|
||||
});
|
||||
if (res.success) {
|
||||
//const turso = createAPIClient({
|
||||
//org: "mikefreno",
|
||||
//token: env.TURSO_DB_API_TOKEN,
|
||||
//});
|
||||
//const res = await turso.databases.delete(db_name); // seems unreliable, using rest api instead
|
||||
const res = await fetch(
|
||||
`https://api.turso.tech/v1/organizations/mikefreno/databases/${db_name}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${env.TURSO_DB_API_TOKEN}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (res.ok) {
|
||||
conn.execute({
|
||||
sql: `DELETE FROM User WHERE email = ?`,
|
||||
args: [email],
|
||||
});
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 200,
|
||||
message: `Account and Database deleted, db dump sent to email: ${send_dump_target}`,
|
||||
});
|
||||
} else {
|
||||
// Shouldn't fail. No idea what the response from turso would be at this point - not documented
|
||||
return NextResponse.json({
|
||||
status: 500,
|
||||
message: "Unknown",
|
||||
ok: false,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 500,
|
||||
message: res.reason,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
//const turso = createAPIClient({
|
||||
//org: "mikefreno",
|
||||
//token: env.TURSO_DB_API_TOKEN,
|
||||
//});
|
||||
//const res = await turso.databases.delete(db_name);
|
||||
const res = await fetch(
|
||||
`https://api.turso.tech/v1/organizations/mikefreno/databases/${db_name}`,
|
||||
{
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${env.TURSO_DB_API_TOKEN}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
if (res.ok) {
|
||||
conn.execute({
|
||||
sql: `DELETE FROM User WHERE email = ?`,
|
||||
args: [email],
|
||||
});
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 200,
|
||||
message: `Account and Database deleted`,
|
||||
});
|
||||
} else {
|
||||
// Shouldn't fail. No idea what the response from turso would be at this point - not documented
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 500,
|
||||
message: "Unknown",
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const insertRes = await conn.execute({
|
||||
sql: `INSERT INTO cron (email, db_name, db_token, send_dump_target) VALUES (?, ?, ?, ?)`,
|
||||
args: [email, db_name, db_token, send_dump_target],
|
||||
});
|
||||
if (insertRes.rowsAffected > 0) {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 200,
|
||||
message: `Deletion scheduled.`,
|
||||
});
|
||||
} else {
|
||||
return NextResponse.json({
|
||||
ok: false,
|
||||
status: 500,
|
||||
message: `Deletion not scheduled, due to server failure`,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
import { LINEAGE_JWT_EXPIRY, LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { checkPassword } from "../../../passwordHashing";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
interface InputData {
|
||||
email: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { email, password } = inputData;
|
||||
if (email && password) {
|
||||
if (password.length < 8) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Invalid Credentials",
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = `SELECT * FROM User WHERE email = ? AND provider = ? LIMIT 1`;
|
||||
const params = [email, "email"];
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
if (res.rows.length == 0) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Invalid Credentials",
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
const user = res.rows[0];
|
||||
if (user.email_verified === 0) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Email not yet verified!",
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
const valid = await checkPassword(password, user.password_hash as string);
|
||||
if (!valid) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Invalid Credentials",
|
||||
}),
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
// create token
|
||||
const token = jwt.sign(
|
||||
{ userId: user.id, email: user.email },
|
||||
env.JWT_SECRET_KEY,
|
||||
{ expiresIn: LINEAGE_JWT_EXPIRY },
|
||||
);
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Login successful",
|
||||
token: token,
|
||||
email: email,
|
||||
});
|
||||
} else {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required fields",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { env } from "@/env.mjs";
|
||||
import { LINEAGE_JWT_EXPIRY } from "@/app/utils";
|
||||
|
||||
export async function GET(req: NextRequest) {
|
||||
const authHeader = req.headers.get("authorization");
|
||||
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
||||
return new NextResponse(JSON.stringify({ valid: false }), { status: 401 });
|
||||
}
|
||||
|
||||
const token = authHeader.split(" ")[1];
|
||||
|
||||
try {
|
||||
const decoded = jwt.verify(token, env.JWT_SECRET_KEY) as jwt.JwtPayload;
|
||||
|
||||
const newToken = jwt.sign(
|
||||
{ userId: decoded.userId, email: decoded.email },
|
||||
env.JWT_SECRET_KEY,
|
||||
{ expiresIn: LINEAGE_JWT_EXPIRY },
|
||||
);
|
||||
|
||||
return NextResponse.json({
|
||||
status: 200,
|
||||
ok: true,
|
||||
valid: true,
|
||||
token: newToken,
|
||||
email: decoded.email,
|
||||
});
|
||||
} catch (error) {
|
||||
return NextResponse.json({ status: 401, ok: false });
|
||||
}
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
interface InputData {
|
||||
email: string;
|
||||
}
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { email } = inputData;
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT * FROM User WHERE email = ?";
|
||||
const params = [email];
|
||||
|
||||
const res = await conn.execute({ sql: query, args: params });
|
||||
|
||||
if (res.rows.length == 0 || res.rows[0].email_verified) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Invalid Request",
|
||||
}),
|
||||
{ status: 409, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
const email_res = await sendEmailVerification(email);
|
||||
const json = await email_res.json();
|
||||
if (json.messageId) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "Email verification sent!",
|
||||
}),
|
||||
{ status: 201, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(json);
|
||||
}
|
||||
}
|
||||
|
||||
async function sendEmailVerification(userEmail: string) {
|
||||
const apiKey = env.SENDINBLUE_KEY as string;
|
||||
const apiUrl = "https://api.sendinblue.com/v3/smtp/email";
|
||||
|
||||
const secretKey = env.JWT_SECRET_KEY;
|
||||
const payload = { email: userEmail };
|
||||
const token = jwt.sign(payload, secretKey, { expiresIn: "15m" });
|
||||
|
||||
const sendinblueData = {
|
||||
sender: {
|
||||
name: "MikeFreno",
|
||||
email: "lifeandlineage_no_reply@freno.me",
|
||||
},
|
||||
to: [
|
||||
{
|
||||
email: userEmail,
|
||||
},
|
||||
],
|
||||
htmlContent: `<html>
|
||||
<head>
|
||||
<style>
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
background-color: #007BFF;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="center">
|
||||
<p>Click the button below to verify email</p>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="center">
|
||||
<a href=${env.NEXT_PUBLIC_DOMAIN}/api/lineage/email/verification/${userEmail}/?token=${token} class="button">Verify Email</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
subject: `Life and Lineage email verification`,
|
||||
};
|
||||
return await fetch(apiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"api-key": apiKey,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(sendinblueData),
|
||||
});
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { hashPassword } from "../../../passwordHashing";
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
import jwt from "jsonwebtoken";
|
||||
import { LibsqlError } from "@libsql/client/web";
|
||||
|
||||
interface InputData {
|
||||
email: string;
|
||||
password: string;
|
||||
password_conf: string;
|
||||
}
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { email, password, password_conf } = inputData;
|
||||
|
||||
if (email && password && password_conf) {
|
||||
if (password == password_conf) {
|
||||
const passwordHash = await hashPassword(password);
|
||||
const conn = LineageConnectionFactory();
|
||||
const userCreationQuery = `
|
||||
INSERT INTO User (email, provider, password_hash)
|
||||
VALUES (?, ?, ?)
|
||||
`;
|
||||
const params = [email, "email", passwordHash];
|
||||
try {
|
||||
await conn.execute({ sql: userCreationQuery, args: params });
|
||||
|
||||
const res = await sendEmailVerification(email);
|
||||
const json = await res.json();
|
||||
if (json.messageId) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "Email verification sent!",
|
||||
}),
|
||||
{ status: 201, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} else {
|
||||
return NextResponse.json(json);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
if (e instanceof LibsqlError && e.code === "SQLITE_CONSTRAINT") {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "User already exists",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "An error occurred while creating the user",
|
||||
}),
|
||||
{ status: 500, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Password mismatch",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required fields",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
async function sendEmailVerification(userEmail: string) {
|
||||
const apiKey = env.SENDINBLUE_KEY as string;
|
||||
const apiUrl = "https://api.sendinblue.com/v3/smtp/email";
|
||||
|
||||
const secretKey = env.JWT_SECRET_KEY;
|
||||
const payload = { email: userEmail };
|
||||
const token = jwt.sign(payload, secretKey, { expiresIn: "15m" });
|
||||
|
||||
const sendinblueData = {
|
||||
sender: {
|
||||
name: "MikeFreno",
|
||||
email: "lifeandlineage_no_reply@freno.me",
|
||||
},
|
||||
to: [
|
||||
{
|
||||
email: userEmail,
|
||||
},
|
||||
],
|
||||
htmlContent: `<html>
|
||||
<head>
|
||||
<style>
|
||||
.center {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
.button {
|
||||
display: inline-block;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: #ffffff;
|
||||
background-color: #007BFF;
|
||||
border-radius: 6px;
|
||||
transition: background-color 0.3s;
|
||||
}
|
||||
.button:hover {
|
||||
background-color: #0056b3;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="center">
|
||||
<p>Click the button below to verify email</p>
|
||||
</div>
|
||||
<br/>
|
||||
<div class="center">
|
||||
<a href=${env.NEXT_PUBLIC_DOMAIN}/api/lineage/email/verification/${userEmail}/?token=${token} class="button">Verify Email</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
subject: `Life and Lineage email verification`,
|
||||
};
|
||||
return await fetch(apiUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"api-key": apiKey,
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(sendinblueData),
|
||||
});
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { env } from "@/env.mjs";
|
||||
import jwt, { JwtPayload } from "jsonwebtoken";
|
||||
import { LineageConnectionFactory, LineageDBInit } from "@/app/utils";
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
context: { params: Promise<{ email: string }> },
|
||||
) {
|
||||
const secretKey = env.JWT_SECRET_KEY;
|
||||
const params = request.nextUrl.searchParams;
|
||||
const token = params.get("token");
|
||||
const userEmail = (await context.params).email;
|
||||
|
||||
let conn;
|
||||
let dbName;
|
||||
let dbToken;
|
||||
|
||||
try {
|
||||
if (!token) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Authentication failed: no token" },
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
const decoded = jwt.verify(token, secretKey) as JwtPayload;
|
||||
if (decoded.email !== userEmail) {
|
||||
return NextResponse.json(
|
||||
{ success: false, message: "Authentication failed: email mismatch" },
|
||||
{ status: 401, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
conn = LineageConnectionFactory();
|
||||
const dbInit = await LineageDBInit();
|
||||
dbName = dbInit.dbName;
|
||||
dbToken = dbInit.token;
|
||||
|
||||
const query = `UPDATE User SET email_verified = ?, database_name = ?, database_token = ? WHERE email = ?`;
|
||||
const queryParams = [true, dbName, dbToken, userEmail];
|
||||
const res = await conn.execute({ sql: query, args: queryParams });
|
||||
|
||||
if (res.rowsAffected === 0) {
|
||||
throw new Error("User not found or update failed");
|
||||
}
|
||||
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message:
|
||||
"Email verification success. You may close this window and sign in within the app.",
|
||||
}),
|
||||
{ status: 202, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Error in email verification:", err);
|
||||
|
||||
// Delete the database if it was created
|
||||
if (dbName) {
|
||||
try {
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
await turso.databases.delete(dbName);
|
||||
console.log(`Database ${dbName} deleted due to error`);
|
||||
} catch (deleteErr) {
|
||||
console.error("Error deleting database:", deleteErr);
|
||||
}
|
||||
}
|
||||
|
||||
// Attempt to revert the User table update if conn is available
|
||||
if (conn) {
|
||||
try {
|
||||
await conn.execute({
|
||||
sql: `UPDATE User SET email_verified = ?, database_name = ?, database_token = ? WHERE email = ?`,
|
||||
args: [false, null, null, userEmail],
|
||||
});
|
||||
console.log("User table update reverted");
|
||||
} catch (revertErr) {
|
||||
console.error("Error reverting User table update:", revertErr);
|
||||
}
|
||||
}
|
||||
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message:
|
||||
"Authentication failed: An error occurred during email verification. Please try again.",
|
||||
}),
|
||||
{ status: 500, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import { LineageConnectionFactory, LineageDBInit } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
import { createClient as createAPIClient } from "@tursodatabase/api";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const { email } = await request.json();
|
||||
if (!email) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "Missing required fields",
|
||||
}),
|
||||
{ status: 400, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
|
||||
const conn = LineageConnectionFactory();
|
||||
|
||||
try {
|
||||
// Check if the user exists
|
||||
const checkUserQuery = "SELECT * FROM User WHERE email = ?";
|
||||
const checkUserResult = await conn.execute({
|
||||
sql: checkUserQuery,
|
||||
args: [email],
|
||||
});
|
||||
|
||||
if (checkUserResult.rows.length > 0) {
|
||||
const updateQuery = `
|
||||
UPDATE User
|
||||
SET provider = ?
|
||||
WHERE email = ?
|
||||
`;
|
||||
const updateRes = await conn.execute({
|
||||
sql: updateQuery,
|
||||
args: ["google", email],
|
||||
});
|
||||
|
||||
if (updateRes.rowsAffected != 0) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "User information updated",
|
||||
}),
|
||||
{ status: 200, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} else {
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "User update failed!",
|
||||
}),
|
||||
{ status: 418, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// User doesn't exist, insert new user and init database
|
||||
let db_name;
|
||||
try {
|
||||
const { token, dbName } = await LineageDBInit();
|
||||
db_name = dbName;
|
||||
console.log("init success");
|
||||
const insertQuery = `
|
||||
INSERT INTO User (email, email_verified, provider, database_name, database_token)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
`;
|
||||
await conn.execute({
|
||||
sql: insertQuery,
|
||||
args: [email, true, "google", dbName, token],
|
||||
});
|
||||
|
||||
console.log("insert success");
|
||||
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: true,
|
||||
message: "New user created",
|
||||
}),
|
||||
{ status: 201, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
} catch (error) {
|
||||
const turso = createAPIClient({
|
||||
org: "mikefreno",
|
||||
token: env.TURSO_DB_API_TOKEN,
|
||||
});
|
||||
await turso.databases.delete(db_name!);
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in Google Sign-Up handler:", error);
|
||||
return new NextResponse(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
message: "An error occurred while processing the request",
|
||||
}),
|
||||
{ status: 500, headers: { "content-type": "application/json" } },
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import playerAttacks from "@/lineage-json/attack-route/playerAttacks.json";
|
||||
import mageBooks from "@/lineage-json/attack-route/mageBooks.json";
|
||||
import mageSpells from "@/lineage-json/attack-route/mageSpells.json";
|
||||
import necroBooks from "@/lineage-json/attack-route/necroBooks.json";
|
||||
import necroSpells from "@/lineage-json/attack-route/necroSpells.json";
|
||||
import rangerBooks from "@/lineage-json/attack-route/rangerBooks.json";
|
||||
import rangerSpells from "@/lineage-json/attack-route/rangerSpells.json";
|
||||
import paladinBooks from "@/lineage-json/attack-route/paladinBooks.json";
|
||||
import paladinSpells from "@/lineage-json/attack-route/paladinSpells.json";
|
||||
import summons from "@/lineage-json/attack-route/summons.json";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
playerAttacks,
|
||||
mageBooks,
|
||||
mageSpells,
|
||||
necroBooks,
|
||||
necroSpells,
|
||||
rangerBooks,
|
||||
rangerSpells,
|
||||
paladinBooks,
|
||||
paladinSpells,
|
||||
summons,
|
||||
});
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
import conditions from "@/lineage-json/conditions-route/conditions.json";
|
||||
import debilitations from "@/lineage-json/conditions-route/debilitations.json";
|
||||
import sanityDebuffs from "@/lineage-json/conditions-route/sanityDebuffs.json";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
conditions,
|
||||
debilitations,
|
||||
sanityDebuffs,
|
||||
});
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import dungeons from "@/lineage-json/dungeon-route/dungeons.json";
|
||||
import specialEncounters from "@/lineage-json/dungeon-route/specialEncounters.json";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ ok: true, dungeons, specialEncounters });
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import bosses from "@/lineage-json/enemy-route/bosses.json";
|
||||
import enemies from "@/lineage-json/enemy-route/enemy.json";
|
||||
import enemyAttacks from "@/lineage-json/enemy-route/enemyAttacks.json";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({ ok: true, bosses, enemies, enemyAttacks });
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import arrows from "@/lineage-json/item-route/arrows.json";
|
||||
import bows from "@/lineage-json/item-route/bows.json";
|
||||
import foci from "@/lineage-json/item-route/foci.json";
|
||||
import hats from "@/lineage-json/item-route/hats.json";
|
||||
import junk from "@/lineage-json/item-route/junk.json";
|
||||
import melee from "@/lineage-json/item-route/melee.json";
|
||||
import robes from "@/lineage-json/item-route/robes.json";
|
||||
import wands from "@/lineage-json/item-route/wands.json";
|
||||
import ingredients from "@/lineage-json/item-route/ingredients.json";
|
||||
import storyItems from "@/lineage-json/item-route/storyItems.json";
|
||||
import artifacts from "@/lineage-json/item-route/artifacts.json";
|
||||
import shields from "@/lineage-json/item-route/shields.json";
|
||||
import bodyArmor from "@/lineage-json/item-route/bodyArmor.json";
|
||||
import helmets from "@/lineage-json/item-route/helmets.json";
|
||||
import suffix from "@/lineage-json/item-route/suffix.json";
|
||||
import prefix from "@/lineage-json/item-route/prefix.json";
|
||||
import potions from "@/lineage-json/item-route/potions.json";
|
||||
import poison from "@/lineage-json/item-route/poison.json";
|
||||
import staves from "@/lineage-json/item-route/staves.json";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
arrows,
|
||||
bows,
|
||||
foci,
|
||||
hats,
|
||||
junk,
|
||||
melee,
|
||||
robes,
|
||||
wands,
|
||||
ingredients,
|
||||
storyItems,
|
||||
artifacts,
|
||||
shields,
|
||||
bodyArmor,
|
||||
helmets,
|
||||
suffix,
|
||||
prefix,
|
||||
potions,
|
||||
poison,
|
||||
staves,
|
||||
});
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import activities from "@/lineage-json/misc-route/activities.json";
|
||||
import investments from "@/lineage-json/misc-route/investments.json";
|
||||
import jobs from "@/lineage-json/misc-route/jobs.json";
|
||||
import manaOptions from "@/lineage-json/misc-route/manaOptions.json";
|
||||
import otherOptions from "@/lineage-json/misc-route/otherOptions.json";
|
||||
import healthOptions from "@/lineage-json/misc-route/healthOptions.json";
|
||||
import sanityOptions from "@/lineage-json/misc-route/sanityOptions.json";
|
||||
import pvpRewards from "@/lineage-json/misc-route/pvpRewards.json";
|
||||
|
||||
export async function GET() {
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
activities,
|
||||
investments,
|
||||
jobs,
|
||||
manaOptions,
|
||||
otherOptions,
|
||||
healthOptions,
|
||||
sanityOptions,
|
||||
pvpRewards,
|
||||
});
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
return new NextResponse(process.env.LINEAGE_OFFLINE_SERIALIZATION_SECRET);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { winnerLinkID, loserLinkID } = await req.json();
|
||||
|
||||
const conn = LineageConnectionFactory();
|
||||
|
||||
try {
|
||||
await conn.execute({
|
||||
sql: `
|
||||
UPDATE PvP_Characters
|
||||
SET
|
||||
winCount = winCount + CASE WHEN linkID = ? THEN 1 ELSE 0 END,
|
||||
lossCount = lossCount + CASE WHEN linkID = ? THEN 1 ELSE 0 END
|
||||
WHERE linkID IN (?, ?)
|
||||
`,
|
||||
args: [winnerLinkID, loserLinkID, winnerLinkID, loserLinkID],
|
||||
});
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
status: 200,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ ok: false, status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { character, linkID, pushToken, pushCurrentlyEnabled } =
|
||||
await req.json();
|
||||
|
||||
try {
|
||||
const conn = LineageConnectionFactory();
|
||||
const res = await conn.execute({
|
||||
sql: `SELECT * FROM PvP_Characters WHERE linkID = ?`,
|
||||
args: [linkID],
|
||||
});
|
||||
if (res.rows.length == 0) {
|
||||
//create
|
||||
await conn.execute({
|
||||
sql: `INSERT INTO PvP_Characters (
|
||||
linkID,
|
||||
blessing,
|
||||
playerClass,
|
||||
name,
|
||||
maxHealth,
|
||||
maxSanity,
|
||||
maxMana,
|
||||
baseManaRegen,
|
||||
strength,
|
||||
intelligence,
|
||||
dexterity,
|
||||
resistanceTable,
|
||||
damageTable,
|
||||
attackStrings,
|
||||
knownSpells,
|
||||
pushToken,
|
||||
pushCurrentlyEnabled
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
args: [
|
||||
linkID,
|
||||
character.playerClass,
|
||||
character.name,
|
||||
character.maxHealth,
|
||||
character.maxSanity,
|
||||
character.maxMana,
|
||||
character.baseManaRegen,
|
||||
character.strength,
|
||||
character.intelligence,
|
||||
character.dexterity,
|
||||
character.resistanceTable,
|
||||
character.damageTable,
|
||||
character.attackStrings,
|
||||
character.knownSpells,
|
||||
pushToken,
|
||||
pushCurrentlyEnabled,
|
||||
],
|
||||
});
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
winCount: 0,
|
||||
lossCount: 0,
|
||||
tokenRedemptionCount: 0,
|
||||
status: 201,
|
||||
});
|
||||
} else {
|
||||
//update
|
||||
await conn.execute({
|
||||
sql: `UPDATE PvP_Characters SET
|
||||
playerClass = ?,
|
||||
blessing = ?,
|
||||
name = ?,
|
||||
maxHealth = ?,
|
||||
maxSanity = ?,
|
||||
maxMana = ?,
|
||||
baseManaRegen = ?,
|
||||
strength = ?,
|
||||
intelligence = ?,
|
||||
dexterity = ?,
|
||||
resistanceTable = ?,
|
||||
damageTable = ?,
|
||||
attackStrings = ?,
|
||||
knownSpells = ?,
|
||||
pushToken = ?,
|
||||
pushCurrentlyEnabled = ?
|
||||
WHERE linkID = ?`,
|
||||
args: [
|
||||
character.playerClass,
|
||||
character.blessing,
|
||||
character.name,
|
||||
character.maxHealth,
|
||||
character.maxSanity,
|
||||
character.maxMana,
|
||||
character.baseManaRegen,
|
||||
character.strength,
|
||||
character.intelligence,
|
||||
character.dexterity,
|
||||
character.resistanceTable,
|
||||
character.damageTable,
|
||||
character.attackStrings,
|
||||
character.knownSpells,
|
||||
pushToken,
|
||||
pushCurrentlyEnabled,
|
||||
linkID,
|
||||
],
|
||||
});
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
winCount: res.rows[0].winCount,
|
||||
lossCount: res.rows[0].lossCount,
|
||||
tokenRedemptionCount: res.rows[0].tokenRedemptionCount,
|
||||
status: 200,
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ ok: false, status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function GET() {
|
||||
// Get three opponents, high, med, low, based on win/loss ratio
|
||||
const conn = LineageConnectionFactory();
|
||||
try {
|
||||
const res = await conn.execute(
|
||||
`
|
||||
SELECT playerClass,
|
||||
blessing,
|
||||
name,
|
||||
maxHealth,
|
||||
maxSanity,
|
||||
maxMana,
|
||||
baseManaRegen,
|
||||
strength,
|
||||
intelligence,
|
||||
dexterity,
|
||||
resistanceTable,
|
||||
damageTable,
|
||||
attackStrings,
|
||||
knownSpells,
|
||||
linkID,
|
||||
winCount,
|
||||
lossCount
|
||||
FROM PvP_Characters
|
||||
ORDER BY RANDOM()
|
||||
LIMIT 3
|
||||
`,
|
||||
);
|
||||
return NextResponse.json({
|
||||
ok: true,
|
||||
characters: res.rows,
|
||||
status: 200,
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ ok: false, status: 500 });
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { LineageConnectionFactory } from "@/app/utils";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const { token } = await req.json();
|
||||
if (!token) {
|
||||
return new NextResponse(
|
||||
JSON.stringify({ success: false, message: "missing token in body" }),
|
||||
{
|
||||
status: 401,
|
||||
},
|
||||
);
|
||||
}
|
||||
const conn = LineageConnectionFactory();
|
||||
const query = "SELECT * FROM Token WHERE token = ?";
|
||||
const res = await conn.execute({ sql: query, args: [token] });
|
||||
if (res.rows.length > 0) {
|
||||
const queryUpdate =
|
||||
"UPDATE Token SET last_updated_at = datetime('now') WHERE token = ?";
|
||||
const resUpdate = await conn.execute({ sql: queryUpdate, args: [token] });
|
||||
return NextResponse.json(JSON.stringify(resUpdate));
|
||||
} else {
|
||||
const queryInsert = "INSERT INTO Token (token) VALUES (?)";
|
||||
const resInsert = await conn.execute({ sql: queryInsert, args: [token] });
|
||||
return NextResponse.json(JSON.stringify(resInsert));
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import * as bcrypt from "bcrypt";
|
||||
|
||||
// Asynchronous function to hash a password
|
||||
export async function hashPassword(password: string): Promise<string> {
|
||||
// 10 here is the number of rounds of hashing to apply
|
||||
// The higher the number, the more secure but also the slower
|
||||
const saltRounds = 10;
|
||||
const salt = await bcrypt.genSalt(saltRounds);
|
||||
const hashedPassword = await bcrypt.hash(password, salt);
|
||||
return hashedPassword;
|
||||
}
|
||||
|
||||
// Asynchronous function to check a password against a hash
|
||||
export async function checkPassword(
|
||||
password: string,
|
||||
hash: string
|
||||
): Promise<boolean> {
|
||||
const match = await bcrypt.compare(password, hash);
|
||||
return match;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import { S3Client, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { NextRequest } from "next/dist/server/web/spec-extension/request";
|
||||
import { NextResponse } from "next/server";
|
||||
import { ConnectionFactory } from "@/app/utils";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
interface InputData {
|
||||
key: string;
|
||||
newAttachmentString: string;
|
||||
type: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { key, newAttachmentString, type, id } = inputData;
|
||||
// Parse the url to get the bucket and key
|
||||
|
||||
const s3params = {
|
||||
Bucket: env.AWS_S3_BUCKET_NAME,
|
||||
Key: key,
|
||||
};
|
||||
|
||||
const client = new S3Client({
|
||||
region: env.AWS_REGION,
|
||||
});
|
||||
|
||||
const command = new DeleteObjectCommand(s3params);
|
||||
const res = await client.send(command);
|
||||
const conn = ConnectionFactory();
|
||||
const query = `UPDATE ${type} SET attachments = ? WHERE id = ?`;
|
||||
const dbparams = [newAttachmentString, id];
|
||||
await conn.execute({ sql: query, args: dbparams });
|
||||
return NextResponse.json(res);
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
interface InputData {
|
||||
type: string;
|
||||
title: string;
|
||||
filename: string;
|
||||
}
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { type, title, filename } = inputData;
|
||||
const credentials = {
|
||||
accessKeyId: env._AWS_ACCESS_KEY,
|
||||
secretAccessKey: env._AWS_SECRET_KEY,
|
||||
};
|
||||
try {
|
||||
const client = new S3Client({
|
||||
region: env.AWS_REGION,
|
||||
credentials: credentials,
|
||||
});
|
||||
const Key = `${type}/${title}/${filename}`;
|
||||
const ext = /^.+\.([^.]+)$/.exec(filename);
|
||||
|
||||
const s3params = {
|
||||
Bucket: env.AWS_S3_BUCKET_NAME,
|
||||
Key,
|
||||
ContentType: `image/${ext![1]}`,
|
||||
};
|
||||
3;
|
||||
const command = new PutObjectCommand(s3params);
|
||||
|
||||
const signedUrl = await getSignedUrl(client, command, { expiresIn: 120 });
|
||||
return NextResponse.json({ uploadURL: signedUrl, key: Key });
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return NextResponse.json({ error: e }, { status: 400 });
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import { S3Client, DeleteObjectCommand } from "@aws-sdk/client-s3";
|
||||
import { NextRequest } from "next/dist/server/web/spec-extension/request";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
import { env } from "@/env.mjs";
|
||||
|
||||
interface InputData {
|
||||
key: string;
|
||||
newAttachmentString: string;
|
||||
type: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export async function POST(input: NextRequest) {
|
||||
const inputData = (await input.json()) as InputData;
|
||||
const { key } = inputData;
|
||||
// Parse the url to get the bucket and key
|
||||
|
||||
const s3params = {
|
||||
Bucket: env.AWS_S3_BUCKET_NAME,
|
||||
Key: key,
|
||||
};
|
||||
|
||||
const client = new S3Client({
|
||||
region: env.AWS_REGION,
|
||||
});
|
||||
|
||||
const command = new DeleteObjectCommand(s3params);
|
||||
const res = await client.send(command);
|
||||
return NextResponse.json(res);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { createHandler, StartServer } from "@solidjs/start/server";
|
||||
import { validateServerEnv } from "./env/server";
|
||||
|
||||
try {
|
||||
const validatedEnv = validateServerEnv(import.meta.env);
|
||||
const validatedEnv = validateServerEnv(process.env);
|
||||
console.log("Environment validation successful");
|
||||
} catch (error) {
|
||||
console.error("Environment validation failed:", error);
|
||||
|
||||
73
src/env/server.ts
vendored
73
src/env/server.ts
vendored
@@ -22,6 +22,19 @@ const serverEnvSchema = z.object({
|
||||
TURSO_LINEAGE_TOKEN: z.string().min(1),
|
||||
TURSO_DB_API_TOKEN: z.string().min(1),
|
||||
LINEAGE_OFFLINE_SERIALIZATION_SECRET: z.string().min(1),
|
||||
// Client-side variables accessible on server
|
||||
VITE_DOMAIN: z.string().min(1).optional(),
|
||||
VITE_AWS_BUCKET_STRING: z.string().min(1).optional(),
|
||||
VITE_GOOGLE_CLIENT_ID: z.string().min(1).optional(),
|
||||
VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE: z.string().min(1).optional(),
|
||||
VITE_GITHUB_CLIENT_ID: z.string().min(1).optional(),
|
||||
VITE_WEBSOCKET: z.string().min(1).optional(),
|
||||
// Aliases for backward compatibility
|
||||
NEXT_PUBLIC_DOMAIN: z.string().min(1).optional(),
|
||||
NEXT_PUBLIC_AWS_BUCKET_STRING: z.string().min(1).optional(),
|
||||
NEXT_PUBLIC_GITHUB_CLIENT_ID: z.string().min(1).optional(),
|
||||
NEXT_PUBLIC_GOOGLE_CLIENT_ID: z.string().min(1).optional(),
|
||||
NEXT_PUBLIC_GOOGLE_CLIENT_ID_MAGIC_DELVE: z.string().min(1).optional(),
|
||||
});
|
||||
|
||||
const clientEnvSchema = z.object({
|
||||
@@ -66,15 +79,21 @@ export const validateServerEnv = (
|
||||
const formattedErrors = error.format();
|
||||
const missingVars = Object.entries(formattedErrors)
|
||||
.filter(
|
||||
([_, value]) =>
|
||||
value._errors.length > 0 && value._errors[0] === "Required",
|
||||
([key, value]) =>
|
||||
key !== "_errors" &&
|
||||
typeof value === "object" &&
|
||||
value._errors?.length > 0 &&
|
||||
value._errors[0] === "Required",
|
||||
)
|
||||
.map(([key, _]) => key);
|
||||
|
||||
const invalidVars = Object.entries(formattedErrors)
|
||||
.filter(
|
||||
([_, value]) =>
|
||||
value._errors.length > 0 && value._errors[0] !== "Required",
|
||||
([key, value]) =>
|
||||
key !== "_errors" &&
|
||||
typeof value === "object" &&
|
||||
value._errors?.length > 0 &&
|
||||
value._errors[0] !== "Required",
|
||||
)
|
||||
.map(([key, value]) => ({
|
||||
key,
|
||||
@@ -116,15 +135,21 @@ export const validateClientEnv = (
|
||||
const formattedErrors = error.format();
|
||||
const missingVars = Object.entries(formattedErrors)
|
||||
.filter(
|
||||
([_, value]) =>
|
||||
value._errors.length > 0 && value._errors[0] === "Required",
|
||||
([key, value]) =>
|
||||
key !== "_errors" &&
|
||||
typeof value === "object" &&
|
||||
value._errors?.length > 0 &&
|
||||
value._errors[0] === "Required",
|
||||
)
|
||||
.map(([key, _]) => key);
|
||||
|
||||
const invalidVars = Object.entries(formattedErrors)
|
||||
.filter(
|
||||
([_, value]) =>
|
||||
value._errors.length > 0 && value._errors[0] !== "Required",
|
||||
([key, value]) =>
|
||||
key !== "_errors" &&
|
||||
typeof value === "object" &&
|
||||
value._errors?.length > 0 &&
|
||||
value._errors[0] !== "Required",
|
||||
)
|
||||
.map(([key, value]) => ({
|
||||
key,
|
||||
@@ -158,8 +183,8 @@ export const validateClientEnv = (
|
||||
// Environment validation for server startup with better error reporting
|
||||
export const env = (() => {
|
||||
try {
|
||||
// Validate server environment variables
|
||||
const validatedServerEnv = validateServerEnv(import.meta.env);
|
||||
// Validate server environment variables using process.env
|
||||
const validatedServerEnv = validateServerEnv(process.env);
|
||||
|
||||
console.log("✅ Environment validation successful");
|
||||
return validatedServerEnv;
|
||||
@@ -194,12 +219,20 @@ export const getClientEnvValidation = () => {
|
||||
|
||||
// Helper function to check if a variable is missing
|
||||
export const isMissingEnvVar = (varName: string): boolean => {
|
||||
return !process.env[varName] || process.env[varName]?.trim() === "";
|
||||
};
|
||||
|
||||
// Helper function to check if a client variable is missing
|
||||
export const isMissingClientEnvVar = (varName: string): boolean => {
|
||||
return !import.meta.env[varName] || import.meta.env[varName]?.trim() === "";
|
||||
};
|
||||
|
||||
// Helper function to get all missing environment variables
|
||||
export const getMissingEnvVars = (): string[] => {
|
||||
const requiredVars = [
|
||||
export const getMissingEnvVars = (): {
|
||||
server: string[];
|
||||
client: string[];
|
||||
} => {
|
||||
const requiredServerVars = [
|
||||
"NODE_ENV",
|
||||
"ADMIN_EMAIL",
|
||||
"ADMIN_ID",
|
||||
@@ -222,5 +255,19 @@ export const getMissingEnvVars = (): string[] => {
|
||||
"LINEAGE_OFFLINE_SERIALIZATION_SECRET",
|
||||
];
|
||||
|
||||
return requiredVars.filter((varName) => isMissingEnvVar(varName));
|
||||
const requiredClientVars = [
|
||||
"VITE_DOMAIN",
|
||||
"VITE_AWS_BUCKET_STRING",
|
||||
"VITE_GOOGLE_CLIENT_ID",
|
||||
"VITE_GOOGLE_CLIENT_ID_MAGIC_DELVE",
|
||||
"VITE_GITHUB_CLIENT_ID",
|
||||
"VITE_WEBSOCKET",
|
||||
];
|
||||
|
||||
return {
|
||||
server: requiredServerVars.filter((varName) => isMissingEnvVar(varName)),
|
||||
client: requiredClientVars.filter((varName) =>
|
||||
isMissingClientEnvVar(varName),
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
1
src/lineage-json/README.md
Normal file
1
src/lineage-json/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Do not directly modify this directory, it is synced from lineage using the script `json-sync.ts`
|
||||
248
src/lineage-json/attack-route/mageBooks.json
Normal file
248
src/lineage-json/attack-route/mageBooks.json
Normal file
@@ -0,0 +1,248 @@
|
||||
[
|
||||
{
|
||||
"name": "book of fire bolt",
|
||||
"type": "spell",
|
||||
"teaches": "fire bolt",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of catch flame",
|
||||
"type": "spell",
|
||||
"teaches": "catch flame",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of scorch",
|
||||
"type": "spell",
|
||||
"teaches": "scorch",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of fireballs",
|
||||
"type": "spell",
|
||||
"teaches": "fireball",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of fire wall",
|
||||
"type": "spell",
|
||||
"teaches": "fire wall",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of rain fire",
|
||||
"type": "spell",
|
||||
"teaches": "rain fire",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden fire techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "dragons breath",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden fire techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "sunbeam",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of frost",
|
||||
"type": "spell",
|
||||
"teaches": "frost",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of water whip",
|
||||
"type": "spell",
|
||||
"teaches": "water whip",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of soothing waters",
|
||||
"type": "spell",
|
||||
"teaches": "soothing waters",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of cone of cold",
|
||||
"type": "spell",
|
||||
"teaches": "cone of cold",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of steam blast",
|
||||
"type": "spell",
|
||||
"teaches": "steam blast",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of ice spike",
|
||||
"type": "spell",
|
||||
"teaches": "ice spike",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of healing rain",
|
||||
"type": "spell",
|
||||
"teaches": "healing rain",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of orb of cold",
|
||||
"type": "spell",
|
||||
"teaches": "orb of cold",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden water techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "torrent",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden water techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "spike field",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of air burst",
|
||||
"type": "spell",
|
||||
"teaches": "air burst",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of sparks",
|
||||
"type": "spell",
|
||||
"teaches": "sparks",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of lightning",
|
||||
"type": "spell",
|
||||
"teaches": "lightning",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of thunder clap",
|
||||
"type": "spell",
|
||||
"teaches": "thunder clap",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of chain lightning",
|
||||
"type": "spell",
|
||||
"teaches": "chain lightning",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of wind blades",
|
||||
"type": "spell",
|
||||
"teaches": "wind blades",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of gale",
|
||||
"type": "spell",
|
||||
"teaches": "surrounding gale",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden air techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "tornado",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden air techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "suffocate",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of rock toss",
|
||||
"type": "spell",
|
||||
"teaches": "rock toss",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of stone hands",
|
||||
"type": "spell",
|
||||
"teaches": "stone hands",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of stone salvo",
|
||||
"type": "spell",
|
||||
"teaches": "stone salvo",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of rock armor",
|
||||
"type": "spell",
|
||||
"teaches": "rock armor",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of stalactite storm",
|
||||
"type": "spell",
|
||||
"teaches": "stalactite storm",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of rock wall",
|
||||
"type": "spell",
|
||||
"teaches": "rock wall",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden earth techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "earthquake",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden earth techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "collider",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
}
|
||||
]
|
||||
|
||||
794
src/lineage-json/attack-route/mageSpells.json
Normal file
794
src/lineage-json/attack-route/mageSpells.json
Normal file
@@ -0,0 +1,794 @@
|
||||
[
|
||||
{
|
||||
"name": "fire bolt",
|
||||
"element": "fire",
|
||||
"proficiencyNeeded": "novice",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"manaCost": 10,
|
||||
"damageTable": {
|
||||
"fire": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "fireMissile",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"scale": 0.3,
|
||||
"reachTargetAtFrame": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "catch flame",
|
||||
"element": "fire",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"fire": 25
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "fireSlash",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "scorch",
|
||||
"element": "fire",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 50,
|
||||
"damageTable": {
|
||||
"fire": 25
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "flameDust",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.6
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fireball",
|
||||
"element": "fire",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"damageTable": {
|
||||
"fire": 60
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "fireMissile",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"scale": 0.7,
|
||||
"reachTargetAtFrame": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fire wall",
|
||||
"element": "fire",
|
||||
"targets": "area",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 100,
|
||||
"maxTurnsActive": 3,
|
||||
"buffNames": [
|
||||
"projectile suppression"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "flameWall",
|
||||
"style": "static",
|
||||
"position": "field",
|
||||
"scale": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rain fire",
|
||||
"element": "fire",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 250,
|
||||
"maxTurnsActive": 5,
|
||||
"damageTable": {
|
||||
"fire": 50
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "fireRain",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dragons breath",
|
||||
"element": "fire",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 600,
|
||||
"damageTable": {
|
||||
"fire": 275
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe burn",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "dragonBreath",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"topOffset": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sunbeam",
|
||||
"element": "fire",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 800,
|
||||
"damageTable": {
|
||||
"fire": 400
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe burn",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "fireBeam",
|
||||
"style": "span",
|
||||
"position": "self",
|
||||
"scale": 1.2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "frost",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 10,
|
||||
"damageTable": {
|
||||
"cold": 10
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "iceBlock",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "water whip",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"physical": 30
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "ambiguousSparks",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "soothing waters",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 50,
|
||||
"selfDamageTable": {
|
||||
"raw": -35
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "splash",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cone of cold",
|
||||
"element": "water",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 100,
|
||||
"damageTable": {
|
||||
"cold": 40
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 1.0
|
||||
},
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "coldSmoke",
|
||||
"style": "span",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "steam blast",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 125,
|
||||
"damageTable": {
|
||||
"fire": 60
|
||||
},
|
||||
"buffNames": null,
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "steam",
|
||||
"style": "span",
|
||||
"position": "enemy",
|
||||
"scale": 0.5,
|
||||
"leftOffset": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ice spike",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 200,
|
||||
"damageTable": {
|
||||
"cold": 100
|
||||
},
|
||||
"buffNames": null,
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "iceSpike",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "healing rain",
|
||||
"element": "water",
|
||||
"proficiencyNeeded": "master",
|
||||
"targets": "area",
|
||||
"type": "defense",
|
||||
"manaCost": 200,
|
||||
"buffNames": [
|
||||
"lasting heal"
|
||||
],
|
||||
"debuffNames": null,
|
||||
"animation": {
|
||||
"sprite": "rainCall",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orb of cold",
|
||||
"element": "water",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 300,
|
||||
"maxTurnsActive": 5,
|
||||
"damageTable": {
|
||||
"cold": 50
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "iceOrb",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.8,
|
||||
"repeat": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "torrent",
|
||||
"element": "water",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 600,
|
||||
"damageTable": {
|
||||
"physical": 400
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "torrent",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spike field",
|
||||
"element": "water",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 700,
|
||||
"maxTurnsActive": 2,
|
||||
"damageTable": {
|
||||
"cold": 150
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "massSpikes",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"retrigger": false,
|
||||
"scale": 1.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "air burst",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 15,
|
||||
"damageTable": {
|
||||
"physical": 18
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "sparks",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 25,
|
||||
"damageTable": {
|
||||
"lightning": 25
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "sparks",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "lightning",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"damageTable": {
|
||||
"lightning": 50
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.5
|
||||
},
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "lightning",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "thunder clap",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 75,
|
||||
"damageTable": {
|
||||
"lightning": 50
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "thunderClap",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "chain lightning",
|
||||
"element": "air",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 105,
|
||||
"damageTable": {
|
||||
"lightning": 70
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "lightningRay",
|
||||
"style": "span",
|
||||
"position": "self",
|
||||
"repeat": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "wind blades",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 100,
|
||||
"damageTable": {
|
||||
"physical": 100
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "windBlades",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "surrounding gale",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 125,
|
||||
"buffNames": [
|
||||
"hard to see",
|
||||
"damaging to hit"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "groundSlash",
|
||||
"style": "static",
|
||||
"position": "self",
|
||||
"repeat": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "tornado",
|
||||
"element": "air",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"maxTurnsActive": 3,
|
||||
"manaCost": 500,
|
||||
"damageTable": {
|
||||
"physical": 100
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "tornado",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 1.4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "suffocate",
|
||||
"element": "air",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"maxTurnsActive": 5,
|
||||
"manaCost": 1250,
|
||||
"damageTable": {
|
||||
"physical": 125
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "suffocate",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rock toss",
|
||||
"element": "earth",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 10,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.10
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "rockDrop",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stone hands",
|
||||
"element": "earth",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"buffNames": [
|
||||
"stone hands"
|
||||
],
|
||||
"debuffNames": null,
|
||||
"animation": {
|
||||
"glow": "#77484C20",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stone salvo",
|
||||
"element": "earth",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"maxTurnsActive": 3,
|
||||
"manaCost": 40,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "rocksDropper",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rock armor",
|
||||
"element": "earth",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 60,
|
||||
"buffNames": [
|
||||
"rock armor"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#77484C20",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stalactite storm",
|
||||
"element": "earth",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 120,
|
||||
"damageTable": {
|
||||
"physical": 90,
|
||||
"raw": 40
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "fallingSpikes",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 4
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rock wall",
|
||||
"element": "earth",
|
||||
"targets": "area",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"maxTurnsActive": 5,
|
||||
"manaCost": 120,
|
||||
"buffNames": [
|
||||
"projectile negation"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "rockWall",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "earthquake",
|
||||
"element": "earth",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 650,
|
||||
"damageTable": {
|
||||
"physical": 120,
|
||||
"raw": 75
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "heavy stun",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#77484895",
|
||||
"position": "field",
|
||||
"triggersScreenShake": {
|
||||
"when": "start",
|
||||
"duration": 1000
|
||||
},
|
||||
"duration": 1000
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "collider",
|
||||
"element": "earth",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 1200,
|
||||
"damageTable": {
|
||||
"physical": 330,
|
||||
"raw": 100
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "heavy stun",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "rockCollider",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 2
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
220
src/lineage-json/attack-route/necroBooks.json
Normal file
220
src/lineage-json/attack-route/necroBooks.json
Normal file
@@ -0,0 +1,220 @@
|
||||
[
|
||||
{
|
||||
"name": "book of pull blood",
|
||||
"type": "spell",
|
||||
"teaches": "pull blood",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of orb burst (mana)",
|
||||
"type": "spell",
|
||||
"teaches": "orb burst(mana)",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of orb burst (health)",
|
||||
"type": "spell",
|
||||
"teaches": "orb burst(health)",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of vampiric touch",
|
||||
"type": "spell",
|
||||
"teaches": "vampiric touch",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of blood spear",
|
||||
"type": "spell",
|
||||
"teaches": "blood spear",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of blood lance",
|
||||
"type": "spell",
|
||||
"teaches": "blood lance",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of blood storm",
|
||||
"type": "spell",
|
||||
"teaches": "blood storm",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden blood techniques",
|
||||
"type": "spell",
|
||||
"teaches": "blood spike",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of the flying skull",
|
||||
"type": "spell",
|
||||
"teaches": "summon flying skull",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of skeleton raising",
|
||||
"type": "spell",
|
||||
"teaches": "raise skeleton",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of zombie raising",
|
||||
"type": "spell",
|
||||
"teaches": "raise zombie",
|
||||
"icon": "Book",
|
||||
"baseValue": 15000
|
||||
},
|
||||
{
|
||||
"name": "book of luch summoning",
|
||||
"type": "spell",
|
||||
"teaches": "summon lich",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of wraith summoning",
|
||||
"type": "spell",
|
||||
"teaches": "summon wraith",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "forbidden summoning techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "summon death knight",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden summoning techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "mass raise dead",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of teeth",
|
||||
"type": "spell",
|
||||
"teaches": "teeth",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of bone shield",
|
||||
"type": "spell",
|
||||
"teaches": "bone shield",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of bone wall",
|
||||
"type": "spell",
|
||||
"teaches": "bone wall",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of bone spear",
|
||||
"type": "spell",
|
||||
"teaches": "bone spear",
|
||||
"icon": "Book",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of bone armor",
|
||||
"type": "spell",
|
||||
"teaches": "bone armor",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of bone armor",
|
||||
"type": "spell",
|
||||
"teaches": "bone armor",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of bone prison",
|
||||
"type": "spell",
|
||||
"teaches": "bone prison",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden bone techniques",
|
||||
"type": "spell",
|
||||
"teaches": "bone blade",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of poison dart",
|
||||
"type": "spell",
|
||||
"teaches": "poison dart",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of plague cloud",
|
||||
"type": "spell",
|
||||
"teaches": "plague cloud",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of poison stream",
|
||||
"type": "spell",
|
||||
"teaches": "poison stream",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of disease ward",
|
||||
"type": "spell",
|
||||
"teaches": "disease ward",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of miasma",
|
||||
"type": "spell",
|
||||
"teaches": "miasma",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of plague bearer",
|
||||
"type": "spell",
|
||||
"teaches": "plague bearer",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of death cloud",
|
||||
"type": "spell",
|
||||
"teaches": "death cloud",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden pestilence techniques",
|
||||
"type": "spell",
|
||||
"teaches": "virulent explosion",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
}
|
||||
]
|
||||
|
||||
580
src/lineage-json/attack-route/necroSpells.json
Normal file
580
src/lineage-json/attack-route/necroSpells.json
Normal file
@@ -0,0 +1,580 @@
|
||||
[
|
||||
{
|
||||
"name": "pull blood",
|
||||
"element": "blood",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"physical": 5
|
||||
},
|
||||
"buffNames": [
|
||||
"blood orb"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodCone",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"leftOffset": 5,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orb burst(mana)",
|
||||
"element": "blood",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": -35,
|
||||
"buffNames": [
|
||||
"consume blood orb"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodBurst",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "orb burst(health)",
|
||||
"element": "blood",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 5,
|
||||
"selfDamageTable": {
|
||||
"raw": -30
|
||||
},
|
||||
"buffNames": [
|
||||
"consume blood orb"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodBurst",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "vampiric touch",
|
||||
"element": "blood",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 65,
|
||||
"damageTable": {
|
||||
"physical": 25
|
||||
},
|
||||
"selfDamageTable": {
|
||||
"raw": -20
|
||||
},
|
||||
"buffNames": [
|
||||
"blood orb"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#7f1d1d80",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blood spear",
|
||||
"element": "blood",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"damageTable": {
|
||||
"physical": 90
|
||||
},
|
||||
"manaCost": 75,
|
||||
"buffNames": [
|
||||
"consume blood orb"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodLongBolts",
|
||||
"style": "span",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blood lance",
|
||||
"element": "blood",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 150,
|
||||
"damageTable": {
|
||||
"physical": 125
|
||||
},
|
||||
"selfDamageTable": {
|
||||
"raw": 25
|
||||
},
|
||||
"buffNames": [
|
||||
"consume blood orb",
|
||||
"consume blood orb"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "hemmorage",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodSimpleBolts",
|
||||
"style": "span",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blood storm",
|
||||
"element": "blood",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 300,
|
||||
"damageTable": {
|
||||
"physical": 200
|
||||
},
|
||||
"selfDamageTable": {
|
||||
"raw": 50
|
||||
},
|
||||
"buffNames": [
|
||||
"blood orb",
|
||||
"blood orb"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "hemmorage",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodRain",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blood spike",
|
||||
"element": "blood",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 750,
|
||||
"damageTable": {
|
||||
"physical": 350
|
||||
},
|
||||
"selfDamageTable": {
|
||||
"raw": 75
|
||||
},
|
||||
"buffNames": [
|
||||
"blood orb",
|
||||
"blood orb",
|
||||
"blood orb"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe hemmorage",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "bloodSpikes",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "summon flying skull",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 50,
|
||||
"summonNames": [
|
||||
"flying skull"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "raise skeleton",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 50,
|
||||
"summonNames": [
|
||||
"skeleton"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "raise zombie",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 50,
|
||||
"summonNames": [
|
||||
"skeleton"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "summon lich",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 150,
|
||||
"summonNames": [
|
||||
"lich"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "summon wraith",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 250,
|
||||
"summonNames": [
|
||||
"wraith"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "summon death knight",
|
||||
"element": "summoning",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 500,
|
||||
"summonNames": [
|
||||
"death knight"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "mass raise dead",
|
||||
"element": "summoning",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 750,
|
||||
"summonNames": [
|
||||
"skeleton",
|
||||
"skeleton",
|
||||
"skeleton"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "teeth",
|
||||
"element": "bone",
|
||||
"targets": "dual",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 15,
|
||||
"damageTable": {
|
||||
"physical": 7
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "teeth",
|
||||
"style": "span",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone shield",
|
||||
"element": "bone",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 15,
|
||||
"buffNames": [
|
||||
"bone shield"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "boneShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone wall",
|
||||
"element": "bone",
|
||||
"targets": "area",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 60,
|
||||
"buffNames": [
|
||||
"projectile suppression"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "boneWall",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone spear",
|
||||
"element": "bone",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 45,
|
||||
"damageTable": {
|
||||
"physical": 40
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "boneLance",
|
||||
"style": "span",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone armor",
|
||||
"element": "bone",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 75,
|
||||
"buffNames": [
|
||||
"guard"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "boneShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone prison",
|
||||
"element": "bone",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 125,
|
||||
"damageTable": {
|
||||
"physical": 100
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "boneOrb",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bone blade",
|
||||
"element": "bone",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 200,
|
||||
"damageTable": {
|
||||
"physical": 300
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "boneBlade",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "poison dart",
|
||||
"element": "pestilence",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"poison": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonDart",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 10,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "plague cloud",
|
||||
"element": "pestilence",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 35,
|
||||
"damageTable": {
|
||||
"poison": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonPuft",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "poison stream",
|
||||
"element": "pestilence",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 60,
|
||||
"damageTable": {
|
||||
"poison": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonStream",
|
||||
"style": "span",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "disease ward",
|
||||
"element": "pestilence",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 50,
|
||||
"buffNames": [
|
||||
"disease immunity"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonShield",
|
||||
"style": "span",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "miasma",
|
||||
"element": "pestilence",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 100,
|
||||
"damageTable": {
|
||||
"poison": 45
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 1.0
|
||||
},
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonOrbBurst",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "plague bearer",
|
||||
"element": "pestilence",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 175,
|
||||
"damageTable": {
|
||||
"poison": 75
|
||||
},
|
||||
"buffNames": [
|
||||
"siphon poison"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#53DF2E",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "death cloud",
|
||||
"element": "pestilence",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 300,
|
||||
"damageTable": {
|
||||
"poison": 150
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 1.0
|
||||
},
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonSmallBurst",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "virulent explosion",
|
||||
"element": "pestilence",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 500,
|
||||
"damageTable": {
|
||||
"poison": 250
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe poison",
|
||||
"chance": 1.0
|
||||
},
|
||||
{
|
||||
"name": "severe disease",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonLargeBurst",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
262
src/lineage-json/attack-route/paladinBooks.json
Normal file
262
src/lineage-json/attack-route/paladinBooks.json
Normal file
@@ -0,0 +1,262 @@
|
||||
[
|
||||
{
|
||||
"name": "book of flash heal",
|
||||
"type": "spell",
|
||||
"teaches": "flash heal",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of minor blessing",
|
||||
"type": "spell",
|
||||
"teaches": "minor blessing",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of holy light",
|
||||
"type": "spell",
|
||||
"teaches": "holy light",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of rejuvenating light",
|
||||
"type": "spell",
|
||||
"teaches": "rejuvenating light",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of turn undead",
|
||||
"type": "spell",
|
||||
"teaches": "turn undead",
|
||||
"icon": "Book",
|
||||
"baseValue": 20000
|
||||
},
|
||||
{
|
||||
"name": "book of cleansing light",
|
||||
"type": "spell",
|
||||
"teaches": "cleansing light",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of delayed heal",
|
||||
"type": "spell",
|
||||
"teaches": "delayed heal",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of moderate heal",
|
||||
"type": "spell",
|
||||
"teaches": "moderate heal",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of holy nova",
|
||||
"type": "spell",
|
||||
"teaches": "holy nova",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of revoke undead",
|
||||
"type": "spell",
|
||||
"teaches": "revoke undead",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of great rejuvenating light",
|
||||
"type": "spell",
|
||||
"teaches": "great rejuvenating light",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "sacred healing techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "overwhelming glow",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "sacred healing techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "unending cure",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of judgment",
|
||||
"type": "spell",
|
||||
"teaches": "judgment",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of righteous fury",
|
||||
"type": "spell",
|
||||
"teaches": "righteous fury",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of holy bolt",
|
||||
"type": "spell",
|
||||
"teaches": "holy bolt",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of holy strike",
|
||||
"type": "spell",
|
||||
"teaches": "holy strike",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of righteous blow",
|
||||
"type": "spell",
|
||||
"teaches": "righteous blow",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of consecrated blade",
|
||||
"type": "spell",
|
||||
"teaches": "consecrated blade",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of holy wrath",
|
||||
"type": "spell",
|
||||
"teaches": "holy wrath",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of smite",
|
||||
"type": "spell",
|
||||
"teaches": "smite",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of holy nova",
|
||||
"type": "spell",
|
||||
"teaches": "holy nova",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of righteous condemnation",
|
||||
"type": "spell",
|
||||
"teaches": "righteous condemnation",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "sacred vengeance techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "divine judgment",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "sacred vengeance techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "holy cataclysm",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of blessed guard",
|
||||
"type": "spell",
|
||||
"teaches": "blessed guard",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of protection aura",
|
||||
"type": "spell",
|
||||
"teaches": "protection aura",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of divine fortitude",
|
||||
"type": "spell",
|
||||
"teaches": "divine fortitude",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of reflective bulwark",
|
||||
"type": "spell",
|
||||
"teaches": "reflective bulwark",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of readied guard",
|
||||
"type": "spell",
|
||||
"teaches": "readied guard",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of holy ward",
|
||||
"type": "spell",
|
||||
"teaches": "holy ward",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of blessed shield",
|
||||
"type": "spell",
|
||||
"teaches": "blessed shield",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of divine resilience",
|
||||
"type": "spell",
|
||||
"teaches": "divine resilience",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of divine intervention",
|
||||
"type": "spell",
|
||||
"teaches": "divine intervention",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of holy sanctuary",
|
||||
"type": "spell",
|
||||
"teaches": "holy sanctuary",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of holy barrier",
|
||||
"type": "spell",
|
||||
"teaches": "holy barrier",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "sacred protection techniques",
|
||||
"type": "spell",
|
||||
"teaches": "aegis of light",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
}
|
||||
]
|
||||
|
||||
708
src/lineage-json/attack-route/paladinSpells.json
Normal file
708
src/lineage-json/attack-route/paladinSpells.json
Normal file
@@ -0,0 +1,708 @@
|
||||
[
|
||||
{
|
||||
"name": "flash heal",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 25,
|
||||
"selfDamageTable": {
|
||||
"raw": -35
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "goldenHeal",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minor blessing",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 15,
|
||||
"buffNames": [
|
||||
"minor fortitude"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy light",
|
||||
"element": "holy",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"holy": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "blind",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#FBD44F",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rejuvenating light",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"buffNames": [
|
||||
"quickened mind"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#FBD44F",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "turn undead",
|
||||
"element": "holy",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 50,
|
||||
"damageTable": {
|
||||
"holy": 20
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "undead cower",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "corruptSword",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cleansing light",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 40,
|
||||
"selfDamageTable": {
|
||||
"raw": -25
|
||||
},
|
||||
"buffNames": [
|
||||
"purify"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#FBD44F",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "delayed heal",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"buffNames": [
|
||||
"delayed heal"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "goldenHeal",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moderate heal",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"selfDamageTable": {
|
||||
"raw": -85
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "goldenHeal",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy nova",
|
||||
"element": "holy",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 85,
|
||||
"damageTable": {
|
||||
"holy": 65
|
||||
},
|
||||
"selfDamageTable": {
|
||||
"raw": -30
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "blind",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyOrb",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "revoke undead",
|
||||
"element": "holy",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 100,
|
||||
"damageTable": {
|
||||
"holy": 75
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "revoke undead",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "corruptSword",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "great rejuvenating light",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 200,
|
||||
"buffNames": [
|
||||
"greater quickened mind"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#FBD44F",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "overwhelming glow",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 200,
|
||||
"selfDamageTable": {
|
||||
"raw": -120
|
||||
},
|
||||
"buffNames": [
|
||||
"overwhelming glow"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyBeam",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "unending cure",
|
||||
"element": "holy",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 250,
|
||||
"duration": 3,
|
||||
"selfDamageTable": {
|
||||
"raw": -100
|
||||
},
|
||||
"buffNames": [
|
||||
"overwhelming glow"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "goldenHeal",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "judgment",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 25,
|
||||
"damageTable": {
|
||||
"holy": 5
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "holyArc",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "righteous fury",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 15,
|
||||
"buffNames": [
|
||||
"minor fury"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "crossedSwords",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy bolt",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"holy": 20
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "holyDart",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"scale": 0.3,
|
||||
"reachTargetAtFrame": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy strike",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 35,
|
||||
"damageTable": {
|
||||
"holy": 35
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "sunder",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "glowingBlade",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "righteous blow",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 40,
|
||||
"damageTable": {
|
||||
"holy": 45
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyFist",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "consecrated blade",
|
||||
"element": "vengeance",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 50,
|
||||
"damageTable": {
|
||||
"holy": 45
|
||||
},
|
||||
"buffNames": [
|
||||
"blessed defense"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "glowingBlade",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy wrath",
|
||||
"element": "vengeance",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 65,
|
||||
"damageTable": {
|
||||
"holy": 55
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "weakened",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShred",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "smite",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 75,
|
||||
"damageTable": {
|
||||
"holy": 85
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holySword",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy nova",
|
||||
"element": "vengeance",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 150,
|
||||
"damageTable": {
|
||||
"holy": 125
|
||||
},
|
||||
"buffNames": [
|
||||
"protection aura"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyTrails",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "righteous condemnation",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 175,
|
||||
"damageTable": {
|
||||
"holy": 150
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "sunder",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "weakened",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "glowingBlade",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "divine judgment",
|
||||
"element": "vengeance",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 200,
|
||||
"damageTable": {
|
||||
"holy": 250
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "execute",
|
||||
"chance": 0.2
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "corruptSword",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy cataclysm",
|
||||
"element": "vengeance",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 300,
|
||||
"damageTable": {
|
||||
"holy": 200
|
||||
},
|
||||
"buffNames": [
|
||||
"righteous fury"
|
||||
],
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe sunder",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holySword",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blessed guard",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 25,
|
||||
"buffNames": [
|
||||
"guard"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "protection aura",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 25,
|
||||
"buffNames": [
|
||||
"protection aura"
|
||||
],
|
||||
"animation": {
|
||||
"glow": "#FBD44F",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "divine fortitude",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"buffNames": [
|
||||
"minor fortitude"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyFist",
|
||||
"style": "static",
|
||||
"position": "field"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "reflective bulwark",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 50,
|
||||
"buffNames": [
|
||||
"reflective bulwark"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "readied guard",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 10,
|
||||
"buffNames": [
|
||||
"empowered guarding"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy ward",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 45,
|
||||
"buffNames": [
|
||||
"spell resistance"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blessed shield",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 65,
|
||||
"buffNames": [
|
||||
"blessed defense"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "divine resilience",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 70,
|
||||
"buffNames": [
|
||||
"fortitude",
|
||||
"spell resistance"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "divine intervention",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 100,
|
||||
"buffNames": [
|
||||
"guard",
|
||||
"blessed defense"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy sanctuary",
|
||||
"element": "protection",
|
||||
"targets": "area",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 125,
|
||||
"selfDamageTable": {
|
||||
"raw": -40
|
||||
},
|
||||
"buffNames": [
|
||||
"protection aura",
|
||||
"minor fortitude"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "holy barrier",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 150,
|
||||
"buffNames": [
|
||||
"protection aura",
|
||||
"reflective bulwark"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "aegis of light",
|
||||
"element": "protection",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "shield",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 250,
|
||||
"buffNames": [
|
||||
"protection aura",
|
||||
"blessed defense",
|
||||
"reflective bulwark"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "holyShield",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
265
src/lineage-json/attack-route/playerAttacks.json
Normal file
265
src/lineage-json/attack-route/playerAttacks.json
Normal file
@@ -0,0 +1,265 @@
|
||||
[
|
||||
{
|
||||
"name": "punch",
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hit",
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stab",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.2
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "smallCross",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "spark",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"lightning": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torch stab",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"fire": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.85
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "slash",
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "slashHorizontal",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cleave",
|
||||
"targets": "dual",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "slashHorizontal",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crushing blow",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "crowning",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "execute",
|
||||
"chance": 0.05
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cast",
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy",
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bonk",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.05
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "crowning",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shoot",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "chainedArrowHit",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rooting shot",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "chainedArrowRooting",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hack",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "execute",
|
||||
"chance": 0.1
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "crowning",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rapid shot",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.55,
|
||||
"damageTable": {},
|
||||
"hits": 3,
|
||||
"animation": {
|
||||
"sprite": "chainedArrowHit",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "careful shot",
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {},
|
||||
"animation": {
|
||||
"sprite": "chainedArrowHit",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "poison shot",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.9,
|
||||
"damageTable": {
|
||||
"poison": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.65
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "chainedPoisonArrowHit",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "overdraw",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.80,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "chainedArrowHit",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
241
src/lineage-json/attack-route/rangerBooks.json
Normal file
241
src/lineage-json/attack-route/rangerBooks.json
Normal file
@@ -0,0 +1,241 @@
|
||||
[
|
||||
{
|
||||
"name": "book of throw shuriken",
|
||||
"type": "spell",
|
||||
"teaches": "throw shuriken",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of poison blade",
|
||||
"type": "spell",
|
||||
"teaches": "poison blade",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of quick strike",
|
||||
"type": "spell",
|
||||
"teaches": "quick strike",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of below the belt",
|
||||
"type": "spell",
|
||||
"teaches": "below the belt",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of dual slice",
|
||||
"type": "spell",
|
||||
"teaches": "dual slice",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of shadow cover",
|
||||
"type": "spell",
|
||||
"teaches": "shadow cover",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of backstab",
|
||||
"type": "spell",
|
||||
"teaches": "backstab",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of venomous strike",
|
||||
"type": "spell",
|
||||
"teaches": "venomous strike",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of dance of daggers",
|
||||
"type": "spell",
|
||||
"teaches": "dance of daggers",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 100000
|
||||
},
|
||||
{
|
||||
"name": "book of garrote",
|
||||
"type": "spell",
|
||||
"teaches": "garrote",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of shadow step",
|
||||
"type": "spell",
|
||||
"teaches": "shadow step",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden assassination techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "blade fan",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden assassination techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "finalé",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
},
|
||||
{
|
||||
"name": "book of the raven",
|
||||
"type": "spell",
|
||||
"teaches": "call raven",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of the wolf",
|
||||
"type": "spell",
|
||||
"teaches": "call wolf",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of animal instinct",
|
||||
"type": "spell",
|
||||
"teaches": "animal instinct",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of rat trap",
|
||||
"type": "spell",
|
||||
"teaches": "rat trap",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of the bear",
|
||||
"type": "spell",
|
||||
"teaches": "call bear",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of beast bond",
|
||||
"type": "spell",
|
||||
"teaches": "beast bond",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of bear trap",
|
||||
"type": "spell",
|
||||
"teaches": "bear trap",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of the dragon welp",
|
||||
"type": "spell",
|
||||
"teaches": "call dragon welp",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of beast fury",
|
||||
"type": "spell",
|
||||
"teaches": "beastial fury",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "book of dragon trap",
|
||||
"type": "spell",
|
||||
"teaches": "dragon trap",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 150000
|
||||
},
|
||||
{
|
||||
"name": "book of the griffon",
|
||||
"type": "spell",
|
||||
"teaches": "call griffon",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "book of entangle",
|
||||
"type": "spell",
|
||||
"teaches": "entangle",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 300000
|
||||
},
|
||||
{
|
||||
"name": "forbidden beast mastery techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "call dragon",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "book of arcane shot",
|
||||
"type": "spell",
|
||||
"teaches": "arcane shot",
|
||||
"icon": "Book",
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "book of enchanted quiver",
|
||||
"type": "spell",
|
||||
"teaches": "enchanted quiver",
|
||||
"icon": "Book",
|
||||
"baseValue": 5000
|
||||
},
|
||||
{
|
||||
"name": "book of arcane arrow",
|
||||
"type": "spell",
|
||||
"teaches": "arcane arrow",
|
||||
"icon": "Book",
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "book of seeking arrow",
|
||||
"type": "spell",
|
||||
"teaches": "seeking arrow",
|
||||
"icon": "Book_2",
|
||||
"baseValue": 50000
|
||||
},
|
||||
{
|
||||
"name": "book of arcane missiles",
|
||||
"type": "spell",
|
||||
"teaches": "arcane missiles",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "book of moon call",
|
||||
"type": "spell",
|
||||
"teaches": "moon call",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 200000
|
||||
},
|
||||
{
|
||||
"name": "forbidden arcane techniques vol. 1",
|
||||
"type": "spell",
|
||||
"teaches": "torrent",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 500000
|
||||
},
|
||||
{
|
||||
"name": "forbidden arcane techniques vol. 2",
|
||||
"type": "spell",
|
||||
"teaches": "moon fire",
|
||||
"icon": "Book_3",
|
||||
"baseValue": 1000000
|
||||
}
|
||||
]
|
||||
|
||||
590
src/lineage-json/attack-route/rangerSpells.json
Normal file
590
src/lineage-json/attack-route/rangerSpells.json
Normal file
@@ -0,0 +1,590 @@
|
||||
[
|
||||
{
|
||||
"name": "throw shuriken",
|
||||
"element": "assassination",
|
||||
"proficiencyNeeded": "novice",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"manaCost": 10,
|
||||
"damageTable": {
|
||||
"physical": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "shuriken",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "poison blade",
|
||||
"element": "assassination",
|
||||
"proficiencyNeeded": "novice",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"manaCost": 15,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"poison": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonDart",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 10,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "quick strike",
|
||||
"element": "assassination",
|
||||
"proficiencyNeeded": "novice",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"manaCost": 10,
|
||||
"damageTable": {
|
||||
"physical": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "slashHorizontal",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "below the belt",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"physical": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "puft",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dual slice",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 25,
|
||||
"damageTable": {
|
||||
"physical": 30
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "smallCross",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow cover",
|
||||
"element": "assassination",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 50,
|
||||
"buffNames": [
|
||||
"stealth"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "smoke",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "backstab",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"damageTable": {
|
||||
"physical": 85,
|
||||
"raw": 10
|
||||
},
|
||||
"buffNames": [
|
||||
"remove stealth"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "slashHit",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "venomous strike",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 60,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"poison": 35
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "severe poison",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "poisonSmallCross",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dance of daggers",
|
||||
"element": "assassination",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 100,
|
||||
"buffNames": [
|
||||
"dance of daggers"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "desaturatedCrossSwords",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "garrote",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 125,
|
||||
"damage": {
|
||||
"physical": 75
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "silence",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"name": "severe bleed",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "crossAndBleed",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shadow step",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 250,
|
||||
"damageTable": {
|
||||
"physical": 100
|
||||
},
|
||||
"buffNames": [
|
||||
"stealth"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "slashAndDust",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "blade fan",
|
||||
"element": "assassination",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 400,
|
||||
"damageTable": {
|
||||
"physical": 275
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "teeth",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "finalé",
|
||||
"element": "assassination",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "melee",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 500,
|
||||
"damageTable": {
|
||||
"physical": 250,
|
||||
"raw": 250
|
||||
},
|
||||
"buffNames": [
|
||||
"remove stealth"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "largeCrossAndBleed",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "call raven",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 10,
|
||||
"rangerPetName": "raven"
|
||||
},
|
||||
{
|
||||
"name": "call wolf",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 15,
|
||||
"rangerPetName": "wolf"
|
||||
},
|
||||
{
|
||||
"name": "animal instinct",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"effects": {
|
||||
"damage": null,
|
||||
"buffNames": [
|
||||
"minor fortitude"
|
||||
],
|
||||
"debuffNames": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rat trap",
|
||||
"element": "beastMastery",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 20,
|
||||
"buffNames": [
|
||||
"rat trap"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "beast bond",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 35,
|
||||
"buffNames": [
|
||||
"beast empowerment"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "call bear",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 50,
|
||||
"rangerPetName": "bear"
|
||||
},
|
||||
{
|
||||
"name": "bear trap",
|
||||
"element": "beastMastery",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 100,
|
||||
"buffNames": [
|
||||
"bear trap"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "call dragon welp",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 125,
|
||||
"rangerPetName": "dragon welp"
|
||||
},
|
||||
{
|
||||
"name": "beastial fury",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 75,
|
||||
"buffNames": [
|
||||
"dual rage"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dragon trap",
|
||||
"element": "beastMastery",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "expert",
|
||||
"manaCost": 200,
|
||||
"buffNames": [
|
||||
"dragon trap"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "call griffon",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 200,
|
||||
"rangerPetName": "griffon"
|
||||
},
|
||||
{
|
||||
"name": "entangle",
|
||||
"element": "beastMastery",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 300,
|
||||
"duration": 5,
|
||||
"damageTable": {
|
||||
"physical": 75
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "call dragon",
|
||||
"element": "beastMastery",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"manaCost": 600,
|
||||
"rangerPetName": "dragon"
|
||||
},
|
||||
{
|
||||
"name": "arcane shot",
|
||||
"element": "arcane",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "novice",
|
||||
"manaCost": 20,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"magic": 5
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "arcaneArrow",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "enchanted quiver",
|
||||
"element": "arcane",
|
||||
"targets": "self",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 25,
|
||||
"buffNames": [
|
||||
"enchanted quiver"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "risingBlue",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arcane arrow",
|
||||
"element": "arcane",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "apprentice",
|
||||
"manaCost": 35,
|
||||
"damageTable": {
|
||||
"physical": 15,
|
||||
"magic": 25
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "arcaneArrow",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "seeking arrow",
|
||||
"element": "arcane",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "adept",
|
||||
"manaCost": 65,
|
||||
"damageTable": {
|
||||
"physical": 35,
|
||||
"magic": 15
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "arcaneArrow",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"scale": 0.3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arcane missiles",
|
||||
"element": "arcane",
|
||||
"targets": "single",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 100,
|
||||
"damageTable": {
|
||||
"magic": 90
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.4
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "risingBlue",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moon call",
|
||||
"element": "arcane",
|
||||
"targets": "self",
|
||||
"type": "defense",
|
||||
"proficiencyNeeded": "master",
|
||||
"manaCost": 125,
|
||||
"buffNames": [
|
||||
"guard",
|
||||
"quickened mind"
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "moonCall",
|
||||
"style": "static",
|
||||
"position": "self"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "torrent",
|
||||
"element": "arcane",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"usesWeapon": "bow",
|
||||
"proficiencyNeeded": "legend",
|
||||
"duration": 3,
|
||||
"manaCost": 500,
|
||||
"damageTable": {
|
||||
"magic": 100
|
||||
},
|
||||
"animation": {
|
||||
"sprite": "arrowTorrent",
|
||||
"style": "missile",
|
||||
"position": "enemy",
|
||||
"reachTargetAtFrame": 7,
|
||||
"topOffset": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "moon fire",
|
||||
"element": "arcane",
|
||||
"targets": "area",
|
||||
"type": "offense",
|
||||
"proficiencyNeeded": "legend",
|
||||
"duration": 5,
|
||||
"manaCost": 1250,
|
||||
"damageTable": {
|
||||
"fire": 25,
|
||||
"magic": 75
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.5
|
||||
}
|
||||
],
|
||||
"animation": {
|
||||
"sprite": "blueBeam",
|
||||
"style": "static",
|
||||
"position": "enemy"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
353
src/lineage-json/attack-route/summons.json
Normal file
353
src/lineage-json/attack-route/summons.json
Normal file
@@ -0,0 +1,353 @@
|
||||
[
|
||||
{
|
||||
"name": "flying skull",
|
||||
"beingType": "undead",
|
||||
"sprite": null,
|
||||
"health": 30,
|
||||
"baseResistanceTable": {
|
||||
"poison": 10,
|
||||
"holy": -50
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 2
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 5
|
||||
},
|
||||
"attackStrings": [
|
||||
"head slam"
|
||||
],
|
||||
"turns": 5
|
||||
},
|
||||
{
|
||||
"name": "skeleton",
|
||||
"beingType": "undead",
|
||||
"health": 50,
|
||||
"sprite": "skeleton",
|
||||
"baseStrength": 5,
|
||||
"baseResistanceTable": {
|
||||
"poison": 10,
|
||||
"holy": -50
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 3
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 5
|
||||
},
|
||||
"attackStrings": [
|
||||
"stab",
|
||||
"cleave"
|
||||
],
|
||||
"turns": 8
|
||||
},
|
||||
{
|
||||
"name": "zombie",
|
||||
"beingType": "undead",
|
||||
"health": 100,
|
||||
"sprite": "zombie",
|
||||
"baseStrength": 8,
|
||||
"baseResistanceTable": {
|
||||
"poison": 10,
|
||||
"fire": -20,
|
||||
"cold": 20,
|
||||
"holy": -75
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 10
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 3
|
||||
},
|
||||
"attackStrings": [
|
||||
"zombie bite",
|
||||
"grab"
|
||||
],
|
||||
"turns": 10
|
||||
},
|
||||
{
|
||||
"name": "wraith",
|
||||
"beingType": "undead",
|
||||
"health": 100,
|
||||
"sprite": "ghost",
|
||||
"baseIntelligence": 15,
|
||||
"baseResistanceTable": {
|
||||
"poison": 40,
|
||||
"fire": -20,
|
||||
"cold": 40,
|
||||
"holy": -50
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"magic": 20
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 75,
|
||||
"regen": 8
|
||||
},
|
||||
"attackStrings": [
|
||||
"life drain",
|
||||
"terrorize"
|
||||
],
|
||||
"turns": 10
|
||||
},
|
||||
{
|
||||
"name": "death knight",
|
||||
"beingType": "undead",
|
||||
"health": 200,
|
||||
"baseStrength": 20,
|
||||
"sprite": null,
|
||||
"baseResistanceTable": {
|
||||
"poison": 40,
|
||||
"fire": 10,
|
||||
"cold": 40,
|
||||
"lightning": -20,
|
||||
"holy": -75
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 35
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 10
|
||||
},
|
||||
"attackStrings": [
|
||||
"soul strike",
|
||||
"death blade",
|
||||
"corrupted cleave"
|
||||
],
|
||||
"turns": 5
|
||||
},
|
||||
{
|
||||
"name": "lich",
|
||||
"beingType": "undead",
|
||||
"health": 175,
|
||||
"baseStrength": 30,
|
||||
"sprite": null,
|
||||
"baseResistanceTable": {
|
||||
"poison": 60,
|
||||
"fire": 15,
|
||||
"cold": 30,
|
||||
"lightning": -20,
|
||||
"holy": -75
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 20,
|
||||
"magic": 32
|
||||
},
|
||||
"mana": {
|
||||
"maximum": 150,
|
||||
"regen": 15
|
||||
},
|
||||
"attackStrings": [
|
||||
"death bolt",
|
||||
"soul rip",
|
||||
"curse"
|
||||
],
|
||||
"turns": 10
|
||||
},
|
||||
{
|
||||
"name": "bandit",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 50,
|
||||
"sprite": "bandit_light",
|
||||
"baseStrength": 8,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 16
|
||||
},
|
||||
"attackStrings": [
|
||||
"stab",
|
||||
"pocket sand",
|
||||
"serrate"
|
||||
],
|
||||
"turns": 100
|
||||
},
|
||||
{
|
||||
"name": "hobgoblin",
|
||||
"beingType": "demi-human",
|
||||
"sanity": null,
|
||||
"health": 160,
|
||||
"sprite": "goblin",
|
||||
"baseStrength": 15,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 24
|
||||
},
|
||||
"attackStrings": [
|
||||
"stab",
|
||||
"frenzy"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "raven",
|
||||
"beingType": "beast",
|
||||
"sprite": null,
|
||||
"health": 50,
|
||||
"baseStrength": 2,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 5
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 5,
|
||||
"lightning": -25,
|
||||
"cold": 10,
|
||||
"fire": -15
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 1
|
||||
},
|
||||
"attackStrings": [
|
||||
"pluck eye",
|
||||
"scratch"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "wolf",
|
||||
"sprite": "wolf_black",
|
||||
"beingType": "beast",
|
||||
"health": 100,
|
||||
"baseStrength": 8,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 10,
|
||||
"cold": 15,
|
||||
"fire": -15
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 8
|
||||
},
|
||||
"attackStrings": [
|
||||
"bite"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "bear",
|
||||
"beingType": "beast",
|
||||
"health": 200,
|
||||
"baseStrength": 10,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 3
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 45,
|
||||
"cold": 30,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 10
|
||||
},
|
||||
"attackStrings": [
|
||||
"bite",
|
||||
"scratch"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "dragon welp",
|
||||
"beingType": "draconic",
|
||||
"health": 225,
|
||||
"baseStrength": 15,
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 15
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 45,
|
||||
"cold": 30,
|
||||
"fire": 75,
|
||||
"lightning": -30
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 8,
|
||||
"fire": 10
|
||||
},
|
||||
"attackStrings": [
|
||||
"bite",
|
||||
"scratch",
|
||||
"fire breath"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "griffon",
|
||||
"beingType": "beast",
|
||||
"health": 300,
|
||||
"baseStrength": 25,
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 45,
|
||||
"cold": 30,
|
||||
"fire": -15,
|
||||
"lightning": -30
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 24
|
||||
},
|
||||
"attackStrings": [
|
||||
"claw",
|
||||
"bite",
|
||||
"wing buffet"
|
||||
],
|
||||
"turns": 1000
|
||||
},
|
||||
{
|
||||
"name": "dragon",
|
||||
"beingType": "draconic",
|
||||
"health": 500,
|
||||
"baseStrength": 30,
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 45,
|
||||
"cold": 30,
|
||||
"fire": 75,
|
||||
"lightning": -30
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 22,
|
||||
"fire": 20
|
||||
},
|
||||
"attackStrings": [
|
||||
"fire breath",
|
||||
"bite",
|
||||
"scratch"
|
||||
],
|
||||
"turns": 1000
|
||||
}
|
||||
]
|
||||
|
||||
1069
src/lineage-json/conditions-route/conditions.json
Normal file
1069
src/lineage-json/conditions-route/conditions.json
Normal file
File diff suppressed because it is too large
Load Diff
134
src/lineage-json/conditions-route/debilitations.json
Normal file
134
src/lineage-json/conditions-route/debilitations.json
Normal file
@@ -0,0 +1,134 @@
|
||||
[
|
||||
{
|
||||
"name": "cataracts",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"accuracy reduction"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.25
|
||||
],
|
||||
"icon": "blind"
|
||||
},
|
||||
{
|
||||
"name": "bad back",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"weaken"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.25
|
||||
],
|
||||
"icon": "broken_sword"
|
||||
},
|
||||
{
|
||||
"name": "bad knee",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"armor decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.25
|
||||
],
|
||||
"icon": "broken_shield"
|
||||
},
|
||||
{
|
||||
"name": "weakened heart",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"healthMax decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.2
|
||||
],
|
||||
"icon": "split_heart"
|
||||
},
|
||||
{
|
||||
"name": "alzheimer's",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"sanityMax decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.5
|
||||
],
|
||||
"icon": "hollow_disk"
|
||||
},
|
||||
{
|
||||
"name": "carpal tunnel",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"weaken"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.1
|
||||
],
|
||||
"icon": "rock_hands"
|
||||
},
|
||||
{
|
||||
"name": "demential",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"sanityMax decrease",
|
||||
"manaMax decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage",
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.15,
|
||||
0.15
|
||||
],
|
||||
"icon": "blank"
|
||||
},
|
||||
{
|
||||
"name": "heart failure",
|
||||
"style": "debuff",
|
||||
"turns": -1,
|
||||
"aura": true,
|
||||
"effect": [
|
||||
"health damage"
|
||||
],
|
||||
"effectStyle": [
|
||||
"flat"
|
||||
],
|
||||
"effectAmount": [
|
||||
10
|
||||
],
|
||||
"icon": "split_heart"
|
||||
}
|
||||
]
|
||||
|
||||
171
src/lineage-json/conditions-route/sanityDebuffs.json
Normal file
171
src/lineage-json/conditions-route/sanityDebuffs.json
Normal file
@@ -0,0 +1,171 @@
|
||||
[
|
||||
{
|
||||
"name": "heart attack",
|
||||
"style": "debuff",
|
||||
"turns": 5,
|
||||
"effect": [
|
||||
"health damage"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.10
|
||||
],
|
||||
"icon": "split_heart"
|
||||
},
|
||||
{
|
||||
"name": "distraught",
|
||||
"style": "debuff",
|
||||
"turns": 3,
|
||||
"effect": [
|
||||
"sanity damage"
|
||||
],
|
||||
"effectStyle": [
|
||||
"flat"
|
||||
],
|
||||
"effectAmount": [
|
||||
5
|
||||
],
|
||||
"icon": "distraught"
|
||||
},
|
||||
{
|
||||
"name": "paranoia",
|
||||
"style": "debuff",
|
||||
"turns": 4,
|
||||
"effect": [
|
||||
"accuracy reduction",
|
||||
"sanity damage"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage",
|
||||
"flat"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.15,
|
||||
2
|
||||
],
|
||||
"icon": "scarecrow"
|
||||
},
|
||||
{
|
||||
"name": "hallucination",
|
||||
"style": "debuff",
|
||||
"turns": 3,
|
||||
"effect": [
|
||||
"accuracy reduction",
|
||||
"blur"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage",
|
||||
null
|
||||
],
|
||||
"effectAmount": [
|
||||
0.25,
|
||||
null
|
||||
],
|
||||
"icon": "blind"
|
||||
},
|
||||
{
|
||||
"name": "trembling",
|
||||
"style": "debuff",
|
||||
"turns": 2,
|
||||
"effect": [
|
||||
"weaken"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.20
|
||||
],
|
||||
"icon": "broken_sword"
|
||||
},
|
||||
{
|
||||
"name": "delirium",
|
||||
"style": "debuff",
|
||||
"turns": 3,
|
||||
"effect": [
|
||||
"sanity damage",
|
||||
"accuracy reduction"
|
||||
],
|
||||
"effectStyle": [
|
||||
"flat",
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
3,
|
||||
0.15
|
||||
],
|
||||
"icon": "viruses"
|
||||
},
|
||||
{
|
||||
"name": "phobia",
|
||||
"style": "debuff",
|
||||
"turns": 4,
|
||||
"effect": [
|
||||
"weaken",
|
||||
"sanity damage"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage",
|
||||
"flat"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.25,
|
||||
2
|
||||
],
|
||||
"icon": "skull_and_crossbones"
|
||||
},
|
||||
{
|
||||
"name": "dissociation",
|
||||
"style": "debuff",
|
||||
"turns": 3,
|
||||
"effect": [
|
||||
"armor decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.30
|
||||
],
|
||||
"icon": "broken_shield"
|
||||
},
|
||||
{
|
||||
"name": "madness_whispers",
|
||||
"style": "debuff",
|
||||
"turns": 4,
|
||||
"effect": [
|
||||
"sanity damage",
|
||||
"silenced"
|
||||
],
|
||||
"effectStyle": [
|
||||
"flat",
|
||||
null
|
||||
],
|
||||
"effectAmount": [
|
||||
2,
|
||||
null
|
||||
],
|
||||
"icon": "hidden"
|
||||
},
|
||||
{
|
||||
"name": "despair",
|
||||
"style": "debuff",
|
||||
"turns": 5,
|
||||
"effect": [
|
||||
"sanityMax decrease",
|
||||
"healthMax decrease"
|
||||
],
|
||||
"effectStyle": [
|
||||
"percentage",
|
||||
"percentage"
|
||||
],
|
||||
"effectAmount": [
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
"icon": "distraught"
|
||||
}
|
||||
]
|
||||
|
||||
1600
src/lineage-json/dungeon-route/dungeons.json
Normal file
1600
src/lineage-json/dungeon-route/dungeons.json
Normal file
File diff suppressed because it is too large
Load Diff
126
src/lineage-json/dungeon-route/specialEncounters.json
Normal file
126
src/lineage-json/dungeon-route/specialEncounters.json
Normal file
@@ -0,0 +1,126 @@
|
||||
[
|
||||
{
|
||||
"name": "camp",
|
||||
"image": "camp",
|
||||
"prompt": "This seems like a good place to rest... Set up camp and rest a while?",
|
||||
"goodOutcome": {
|
||||
"chance": 0.25,
|
||||
"message": "You awaken massively restored.",
|
||||
"result": {
|
||||
"effect": {
|
||||
"sanity": 50,
|
||||
"health": 50
|
||||
}
|
||||
}
|
||||
},
|
||||
"neutralOutcome": {
|
||||
"chance": 0.65,
|
||||
"message": "You feel rested.",
|
||||
"result": {
|
||||
"effect": {
|
||||
"sanity": 10,
|
||||
"health": 10
|
||||
}
|
||||
}
|
||||
},
|
||||
"badOutcome": {
|
||||
"chance": 0.1,
|
||||
"message": "Ambush! Prepare for battle!",
|
||||
"result": {
|
||||
"battle": [
|
||||
"bandit"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "chest",
|
||||
"image": "chest",
|
||||
"prompt": "You come across a chest. Do you open it?",
|
||||
"goodOutcome": {
|
||||
"chance": 0.65,
|
||||
"message": "For the explorer, the spoils...",
|
||||
"result": {
|
||||
"drops": [
|
||||
{
|
||||
"name": "iron chestpiece",
|
||||
"itemType": "bodyArmor",
|
||||
"chance": 0.1
|
||||
}
|
||||
],
|
||||
"gold": {
|
||||
"min": 50,
|
||||
"max": 250
|
||||
}
|
||||
}
|
||||
},
|
||||
"neutralOutcome": {
|
||||
"chance": 0.25,
|
||||
"message": "The chest appears to already have been looted, also you got a splinter",
|
||||
"result": {
|
||||
"effect": {
|
||||
"sanity": -5,
|
||||
"health": -1
|
||||
}
|
||||
}
|
||||
},
|
||||
"badOutcome": {
|
||||
"chance": 0.10,
|
||||
"message": "There is more here than it seems... Prepare for battle!",
|
||||
"result": {
|
||||
"battle": [
|
||||
"mimic"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ritual altar",
|
||||
"image": "ritual_altar",
|
||||
"prompt": "You come across an ominous altar. Do you approach it?",
|
||||
"goodOutcome": {
|
||||
"chance": 0.5,
|
||||
"message": "A soothing calm comes over you...",
|
||||
"result": {
|
||||
"effect": {
|
||||
"health": 50,
|
||||
"sanity": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"badOutcome": {
|
||||
"chance": 0.5,
|
||||
"message": "A feeling of dread overwhelms you.",
|
||||
"result": {
|
||||
"effect": {
|
||||
"sanity": -30
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "water basin",
|
||||
"image": "water_basin",
|
||||
"prompt": "You come across an ominous altar. Do you approach it?",
|
||||
"goodOutcome": {
|
||||
"chance": 0.5,
|
||||
"message": "A soothing calm comes over you...",
|
||||
"result": {
|
||||
"effect": {
|
||||
"health": 50,
|
||||
"sanity": 30
|
||||
}
|
||||
}
|
||||
},
|
||||
"badOutcome": {
|
||||
"chance": 0.5,
|
||||
"message": "A feeling of dread overwhelms you.",
|
||||
"result": {
|
||||
"effect": {
|
||||
"sanity": -30
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
900
src/lineage-json/enemy-route/bosses.json
Normal file
900
src/lineage-json/enemy-route/bosses.json
Normal file
@@ -0,0 +1,900 @@
|
||||
[
|
||||
{
|
||||
"name": "zombie",
|
||||
"sprite": "zombie",
|
||||
"beingType": "undead",
|
||||
"sanity": null,
|
||||
"health": 80,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 5
|
||||
},
|
||||
"attackStrings": [
|
||||
"grab",
|
||||
"zombie bite"
|
||||
],
|
||||
"animationStrings": {
|
||||
"grab": "attack_1",
|
||||
"zombie bite": "attack_1"
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": 75,
|
||||
"fire": 15,
|
||||
"cold": 15,
|
||||
"holy": -50
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 6
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "chunk of flesh",
|
||||
"itemType": "junk",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"item": "chunk of flesh",
|
||||
"itemType": "junk",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 100,
|
||||
"maximum": 150
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "necromancer",
|
||||
"beingType": "human",
|
||||
"sprite": "necromancer",
|
||||
"sanity": 50,
|
||||
"health": 130,
|
||||
"mana": {
|
||||
"maximum": 80,
|
||||
"regen": 8
|
||||
},
|
||||
"attackStrings": [
|
||||
"dark burst",
|
||||
"raise skeleton",
|
||||
"terrorize"
|
||||
],
|
||||
"animationStrings": {
|
||||
"dark burst": "attack_1",
|
||||
"raise skeleton": "attack_2",
|
||||
"terrorize": "attack_3"
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": 10,
|
||||
"fire": 5,
|
||||
"cold": 15,
|
||||
"holy": -20
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 8
|
||||
},
|
||||
"phases": [
|
||||
{
|
||||
"triggerHealth": 0,
|
||||
"health": 70,
|
||||
"sprite": "reaper",
|
||||
"dialogue": {
|
||||
"1": "Witness my true power!"
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": 50,
|
||||
"fire": 15,
|
||||
"cold": 30,
|
||||
"holy": -75
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"poison": 5,
|
||||
"cold": 12
|
||||
},
|
||||
"attackStrings": [
|
||||
"soul strike",
|
||||
"death blade"
|
||||
],
|
||||
"animationStrings": {
|
||||
"soul strike": "attack_1",
|
||||
"death blade": "attack_2"
|
||||
}
|
||||
}
|
||||
],
|
||||
"drops": [
|
||||
{
|
||||
"item": "dagger",
|
||||
"itemType": "melee",
|
||||
"chance": 0.15
|
||||
},
|
||||
{
|
||||
"item": "dagger",
|
||||
"itemType": "melee",
|
||||
"chance": 0.15
|
||||
},
|
||||
{
|
||||
"item": "adept robes",
|
||||
"itemType": "robe",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"storyDrops": [
|
||||
{
|
||||
"item": "the deed to the whispering raven inn"
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 250,
|
||||
"maximum": 450
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "kobold",
|
||||
"beingType": "demi-human",
|
||||
"sprite": "kobold",
|
||||
"sanity": null,
|
||||
"health": 160,
|
||||
"mana": {
|
||||
"maximum": 60,
|
||||
"regen": 15
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"lightning": 15,
|
||||
"cold": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 6,
|
||||
"lightning": 10
|
||||
},
|
||||
"attackStrings": [
|
||||
"stab",
|
||||
"cleave",
|
||||
"chop",
|
||||
"charged pierce"
|
||||
],
|
||||
"animationStrings": {
|
||||
"stab": "attack_1",
|
||||
"cleave": "attack_2",
|
||||
"chop": "attack_3",
|
||||
"charged pierce": "attack_4"
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "longsword",
|
||||
"itemType": "melee",
|
||||
"chance": 0.65
|
||||
},
|
||||
{
|
||||
"item": "longsword",
|
||||
"itemType": "melee",
|
||||
"chance": 0.65
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 100,
|
||||
"maximum": 150
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "goblin mage",
|
||||
"sprite": "goblin_mage",
|
||||
"beingType": "demi-human",
|
||||
"sanity": 50,
|
||||
"health": 140,
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 10,
|
||||
"poison": -5,
|
||||
"lightning": -5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"magic": 16
|
||||
},
|
||||
"attackStrings": [
|
||||
"pulse",
|
||||
"dark bolt"
|
||||
],
|
||||
"animationStrings": {
|
||||
"pulse": "attack_1",
|
||||
"dark bolt": "attack_2"
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "goblin totem",
|
||||
"itemType": "staff",
|
||||
"chance": 1.0
|
||||
}
|
||||
],
|
||||
"storyDrops": [
|
||||
{
|
||||
"item": "head of goblin shaman"
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 100,
|
||||
"maximum": 150
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "warg",
|
||||
"sprite": "wolf_black",
|
||||
"beingType": "beast",
|
||||
"sanity": null,
|
||||
"health": 160,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 5
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"cold": 10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 18
|
||||
},
|
||||
"attackStrings": [
|
||||
"bite",
|
||||
"claw"
|
||||
],
|
||||
"animationStrings": {
|
||||
"bite": "attack_1",
|
||||
"claw": "attack_2"
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "patch of hair",
|
||||
"itemType": "junk",
|
||||
"chance": 0.85
|
||||
},
|
||||
{
|
||||
"item": "patch of hair",
|
||||
"itemType": "junk",
|
||||
"chance": 0.85
|
||||
},
|
||||
{
|
||||
"item": "bone",
|
||||
"itemType": "ingredient",
|
||||
"chance": 0.75
|
||||
},
|
||||
{
|
||||
"item": "bone",
|
||||
"itemType": "ingredient",
|
||||
"chance": 0.75
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 40,
|
||||
"maximum": 55
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bandit",
|
||||
"beingType": "human",
|
||||
"sprite": "bandit_light",
|
||||
"sanity": 50,
|
||||
"health": 75,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 3
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 16
|
||||
},
|
||||
"attackStrings": [
|
||||
"stab",
|
||||
"pocket sand",
|
||||
"serrate"
|
||||
],
|
||||
"animationStrings": {
|
||||
"stab": "attack_1",
|
||||
"pocket sand": "attack_1",
|
||||
"serrate": "attack_1"
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "shortsword",
|
||||
"itemType": "melee",
|
||||
"chance": 0.15
|
||||
},
|
||||
{
|
||||
"item": "cheap leather chestpiece",
|
||||
"itemType": "bodyArmor",
|
||||
"chance": 0.15
|
||||
},
|
||||
{
|
||||
"item": "leather headgear",
|
||||
"itemType": "helmet",
|
||||
"chance": 0.15
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 70,
|
||||
"maximum": 100
|
||||
},
|
||||
"armorValue": 15
|
||||
},
|
||||
{
|
||||
"name": "bandit heavy",
|
||||
"sprite": "bandit_heavy",
|
||||
"beingType": "human",
|
||||
"sanity": 25,
|
||||
"health": 155,
|
||||
"mana": {
|
||||
"maximum": 30,
|
||||
"regen": 2
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 25,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 14
|
||||
},
|
||||
"attackStrings": [
|
||||
"pommel strike",
|
||||
"heavy swing"
|
||||
],
|
||||
"animationStrings": {
|
||||
"pommel strike": "attack_1",
|
||||
"heavy swing": "attack_1"
|
||||
},
|
||||
"drops": [
|
||||
{
|
||||
"item": "longsword",
|
||||
"itemType": "melee",
|
||||
"chance": 0.25
|
||||
},
|
||||
{
|
||||
"item": "cheap iron chestpiece",
|
||||
"itemType": "bodyArmor",
|
||||
"chance": 0.25
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 80,
|
||||
"maximum": 100
|
||||
},
|
||||
"armorValue": 15
|
||||
},
|
||||
{
|
||||
"name": "huge knight",
|
||||
"beingType": "human",
|
||||
"sprite": "huge_knight",
|
||||
"sanity": 50,
|
||||
"health": 200,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 35,
|
||||
"poison": -15,
|
||||
"cold": -20,
|
||||
"fire": -15
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 18
|
||||
},
|
||||
"attackStrings": [
|
||||
"heavy swing",
|
||||
"call backup",
|
||||
"stab"
|
||||
],
|
||||
"animationStrings": {
|
||||
"heavy swing": "attack_1",
|
||||
"call backup": "attack_1",
|
||||
"stab": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [
|
||||
{
|
||||
"item": "broken seal contract"
|
||||
}
|
||||
],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 30
|
||||
},
|
||||
{
|
||||
"name": "giant venomous spider",
|
||||
"beingType": "beast",
|
||||
"sprite": "spider_default",
|
||||
"sanity": null,
|
||||
"health": 140,
|
||||
"mana": {
|
||||
"maximum": 40,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": 75,
|
||||
"cold": -10,
|
||||
"lightning": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 10,
|
||||
"poison": 20
|
||||
},
|
||||
"attackStrings": [
|
||||
"venomous bite"
|
||||
],
|
||||
"animationStrings": {
|
||||
"venomous bite": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 40,
|
||||
"maximum": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "brood mother",
|
||||
"beingType": "beast",
|
||||
"sprite": "spider_default_brood",
|
||||
"sanity": null,
|
||||
"health": 240,
|
||||
"mana": {
|
||||
"maximum": 40,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": 75,
|
||||
"cold": -10,
|
||||
"lightning": -10,
|
||||
"fire": -10
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 4,
|
||||
"poison": 20
|
||||
},
|
||||
"attackStrings": [
|
||||
"venomous bite"
|
||||
],
|
||||
"animationStrings": {
|
||||
"venomous bite": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 40,
|
||||
"maximum": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "adept air mage",
|
||||
"beingType": "human",
|
||||
"sprite": "wizard_gray",
|
||||
"sanity": 50,
|
||||
"health": 150,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 36
|
||||
},
|
||||
"attackStrings": [
|
||||
"bonk",
|
||||
"gust"
|
||||
],
|
||||
"animationStrings": {
|
||||
"gust": "attack_1",
|
||||
"bonk": "attack_2"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 10
|
||||
},
|
||||
{
|
||||
"name": "adept water mage",
|
||||
"sprite": "wizard_classic",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 150,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"cold": 35
|
||||
},
|
||||
"attackStrings": [
|
||||
"bonk",
|
||||
"frost"
|
||||
],
|
||||
"animationStrings": {
|
||||
"frost": "attack_1",
|
||||
"bonk": "attack_2"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 10
|
||||
},
|
||||
{
|
||||
"name": "master earthen monk",
|
||||
"sprite": "ground_monk",
|
||||
"beingType": "human",
|
||||
"sanity": 100,
|
||||
"health": 190,
|
||||
"mana": {
|
||||
"maximum": 100,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 10,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 24,
|
||||
"raw": 16
|
||||
},
|
||||
"attackStrings": [
|
||||
"kick",
|
||||
"punch",
|
||||
"flurry",
|
||||
"rock spike",
|
||||
"burial"
|
||||
],
|
||||
"animationStrings": {
|
||||
"kick": "attack_1",
|
||||
"punch": "attack_2",
|
||||
"flurry": "attack_3",
|
||||
"rock spike": "attack_4",
|
||||
"burial": "attack_5"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 10
|
||||
},
|
||||
{
|
||||
"name": "master fire mage",
|
||||
"sprite": "pyromancer",
|
||||
"beingType": "human",
|
||||
"sanity": 100,
|
||||
"health": 180,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 10,
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": 50,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"fire": 40
|
||||
},
|
||||
"attackStrings": [
|
||||
"fire bolt"
|
||||
],
|
||||
"animationStrings": {
|
||||
"fire bolt": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 10
|
||||
},
|
||||
{
|
||||
"name": "centaur",
|
||||
"beingType": "demi-human",
|
||||
"sprite": "centaur",
|
||||
"sanity": 50,
|
||||
"health": 200,
|
||||
"mana": {
|
||||
"maximum": 40,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": 20,
|
||||
"cold": -5,
|
||||
"holy": 25
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 45
|
||||
},
|
||||
"attackStrings": [
|
||||
"stampede",
|
||||
"chop"
|
||||
],
|
||||
"animationStrings": {
|
||||
"chop": "attack_1",
|
||||
"stampede": "attack_2"
|
||||
},
|
||||
"drops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 40,
|
||||
"maximum": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gryphon",
|
||||
"sprite": "gryphon",
|
||||
"beingType": "beast",
|
||||
"sanity": null,
|
||||
"health": 225,
|
||||
"mana": {
|
||||
"maximum": 60,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"physical": 15,
|
||||
"poison": 20,
|
||||
"cold": 10,
|
||||
"holy": 25,
|
||||
"lightning": -35
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 45
|
||||
},
|
||||
"attackStrings": [
|
||||
"claw",
|
||||
"wing buffet"
|
||||
],
|
||||
"animationStrings": {
|
||||
"claw": "attack_1",
|
||||
"wing buffet": "attack_2"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 10
|
||||
},
|
||||
{
|
||||
"name": "gladiator",
|
||||
"sprite": "gladiator_ls",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 220,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 40
|
||||
},
|
||||
"attackStrings": [
|
||||
"pierce"
|
||||
],
|
||||
"animationStrings": {
|
||||
"pierce": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
},
|
||||
{
|
||||
"name": "lizardman",
|
||||
"sprite": "lizardman",
|
||||
"beingType": "demi-human",
|
||||
"sanity": null,
|
||||
"health": 180,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": 35,
|
||||
"cold": 70,
|
||||
"fire": 30,
|
||||
"holy": 5,
|
||||
"lightning": -5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 40,
|
||||
"poison": 10
|
||||
},
|
||||
"attackStrings": [
|
||||
"cleave"
|
||||
],
|
||||
"animationStrings": {
|
||||
"cleave": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
},
|
||||
{
|
||||
"name": "the hammer",
|
||||
"sprite": "gladiator_hammer",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 295,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 40,
|
||||
"raw": 15
|
||||
},
|
||||
"attackStrings": [
|
||||
"heavy swing"
|
||||
],
|
||||
"animationStrings": {
|
||||
"heavy swing": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
},
|
||||
{
|
||||
"name": "the spear",
|
||||
"sprite": "gladiator_spear",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 270,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 55
|
||||
},
|
||||
"attackStrings": [
|
||||
"pierce"
|
||||
],
|
||||
"animationStrings": {
|
||||
"pierce": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
},
|
||||
{
|
||||
"name": "the deadeye",
|
||||
"sprite": "gladiator_archer",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 245,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 5
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 55
|
||||
},
|
||||
"attackStrings": [
|
||||
"shoot"
|
||||
],
|
||||
"animationStrings": {
|
||||
"shoot": "attack_1"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
},
|
||||
{
|
||||
"name": "her",
|
||||
"sprite": "gladiator_female",
|
||||
"beingType": "human",
|
||||
"sanity": 50,
|
||||
"health": 285,
|
||||
"attackPower": 30,
|
||||
"mana": {
|
||||
"maximum": 50,
|
||||
"regen": 10
|
||||
},
|
||||
"baseResistanceTable": {
|
||||
"poison": -15,
|
||||
"cold": -10,
|
||||
"fire": -10,
|
||||
"holy": 15
|
||||
},
|
||||
"baseDamageTable": {
|
||||
"physical": 60
|
||||
},
|
||||
"attackStrings": [
|
||||
"cleave",
|
||||
"stab"
|
||||
],
|
||||
"animationStrings": {
|
||||
"cleave": "attack_1",
|
||||
"stab": "attack_2"
|
||||
},
|
||||
"drops": [],
|
||||
"storyDrops": [],
|
||||
"goldDropRange": {
|
||||
"minimum": 2500,
|
||||
"maximum": 3000
|
||||
},
|
||||
"armorValue": 50
|
||||
}
|
||||
]
|
||||
|
||||
1112
src/lineage-json/enemy-route/enemy.json
Normal file
1112
src/lineage-json/enemy-route/enemy.json
Normal file
File diff suppressed because it is too large
Load Diff
854
src/lineage-json/enemy-route/enemyAttacks.json
Normal file
854
src/lineage-json/enemy-route/enemyAttacks.json
Normal file
@@ -0,0 +1,854 @@
|
||||
[
|
||||
{
|
||||
"name": "stab",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.20
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "serrate",
|
||||
"manaCost": 15,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "hemmorage",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bite",
|
||||
"manaCost": 8,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 0.10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "zombie bite",
|
||||
"manaCost": 15,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 3,
|
||||
"poison": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "diseased",
|
||||
"chance": 0.50
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "vampiric bite",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 4,
|
||||
"poison": 1
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "lifesteal",
|
||||
"chance": 0.65
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "venomous bite",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 2,
|
||||
"poison": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.65
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "torch stab",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 2,
|
||||
"fire": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "cleave",
|
||||
"manaCost": 10,
|
||||
"targets": "dual",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "blunt cleave",
|
||||
"manaCost": 10,
|
||||
"targets": "dual",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 3,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "kick",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rock throw",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "rock spike",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.65
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "burial",
|
||||
"manaCost": 75,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 20
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "heavy stun",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "grab",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.75,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "tackle",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.75,
|
||||
"damageTable": {
|
||||
"physical": 3,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.8
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stomp",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 2,
|
||||
"raw": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bolder throw",
|
||||
"manaCost": 25,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"physical": 2,
|
||||
"raw": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pocket sand",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"raw": 1
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "blind",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "poison spray",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"poison": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.85
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "poisoned shot",
|
||||
"manaCost": 15,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"poison": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "poison",
|
||||
"chance": 0.5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "maddening shot",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {},
|
||||
"sanityDamage": 5
|
||||
},
|
||||
{
|
||||
"name": "wail",
|
||||
"manaCost": 20,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {},
|
||||
"sanityDamage": 5,
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "fear",
|
||||
"chance": 0.50
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "shoot",
|
||||
"manaCost": 15,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.75,
|
||||
"damageTable": {
|
||||
"physical": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "head slam",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"raw": 2,
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stampede",
|
||||
"manaCost": 15,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"raw": 2,
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.50
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "heavy swing",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.80,
|
||||
"damageTable": {
|
||||
"physical": 10
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.20
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "flurry",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.65,
|
||||
"hitsPerTurn": 4,
|
||||
"damageTable": {
|
||||
"physical": 5,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.15
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "chop",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 6
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "headbutt",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"raw": 2,
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.20
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pommel strike",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"raw": 2,
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.20
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "punch",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "call backup",
|
||||
"manaCost": 30,
|
||||
"damageTable": {},
|
||||
"summonNames": [
|
||||
"bandit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "raise skeleton",
|
||||
"damageTable": {},
|
||||
"manaCost": 35,
|
||||
"summonNames": [
|
||||
"skeleton"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "teeth",
|
||||
"manaCost": 15,
|
||||
"targets": "dual",
|
||||
"damageTable": {
|
||||
"raw": 6,
|
||||
"physical": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "frenzy",
|
||||
"damageTable": {},
|
||||
"manaCost": 10,
|
||||
"buffNames": [
|
||||
"frenzy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "chug beer",
|
||||
"damageTable": {},
|
||||
"manaCost": 10,
|
||||
"buffNames": [
|
||||
"frenzy"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spark",
|
||||
"manaCost": 25,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"lightning": 6
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bonk",
|
||||
"manaCost": 5,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pluck eye",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 3
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "blind",
|
||||
"chance": 0.9
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "scratch",
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pulse",
|
||||
"manaCost": 10,
|
||||
"target": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"magic": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dark burst",
|
||||
"manaCost": 15,
|
||||
"target": "area",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"poison": 2,
|
||||
"physical": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dark bolt",
|
||||
"manaCost": 20,
|
||||
"target": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"poison": 3,
|
||||
"physical": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "fire bolt",
|
||||
"manaCost": 20,
|
||||
"target": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"fire": 10
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "frost",
|
||||
"manaCost": 20,
|
||||
"target": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"cold": 6
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "chill",
|
||||
"chance": 0.5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "gust",
|
||||
"manaCost": 10,
|
||||
"target": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 6
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rock toss",
|
||||
"manaCost": 15,
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"physical": 4,
|
||||
"raw": 2
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.10
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "life drain",
|
||||
"manaCost": 25,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"raw": 5
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "lifesteal",
|
||||
"chance": 0.5
|
||||
},
|
||||
{
|
||||
"name": "dulled mind",
|
||||
"chance": 0.35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "terrorize",
|
||||
"manaCost": 30,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.85,
|
||||
"sanityDamage": 10,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "fear",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soul strike",
|
||||
"manaCost": 20,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"raw": 6
|
||||
},
|
||||
"sanityDamage": 5
|
||||
},
|
||||
{
|
||||
"name": "death blade",
|
||||
"manaCost": 25,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"raw": 12
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "hemmorage",
|
||||
"chance": 0.50
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "corrupted cleave",
|
||||
"manaCost": 35,
|
||||
"targets": "dual",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"raw": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "necrotic wound",
|
||||
"chance": 0.45
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "death bolt",
|
||||
"manaCost": 30,
|
||||
"targets": "single",
|
||||
"baseHitChance": 1.0,
|
||||
"damageTable": {
|
||||
"raw": 15
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "necrotic wound",
|
||||
"chance": 0.65
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "soul rip",
|
||||
"manaCost": 45,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"sanityDamage": 15,
|
||||
"damageTable": {
|
||||
"raw": 20
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "dulled mind",
|
||||
"chance": 0.75
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "curse",
|
||||
"manaCost": 40,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "death mark",
|
||||
"chance": 1.0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "claw",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 4
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "bleed",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "dive",
|
||||
"manaCost": 15,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.80,
|
||||
"damageTable": {
|
||||
"physical": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gust",
|
||||
"manaCost": 15,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.95,
|
||||
"damageTable": {
|
||||
"physical": 6
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "fire breath",
|
||||
"manaCost": 20,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"fire": 6
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "burn",
|
||||
"chance": 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "wing buffet",
|
||||
"manaCost": 25,
|
||||
"targets": "area",
|
||||
"baseHitChance": 0.90,
|
||||
"damageTable": {
|
||||
"physical": 8
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "stun",
|
||||
"chance": 0.25
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pierce",
|
||||
"manaCost": 10,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"physical": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "charged pierce",
|
||||
"manaCost": 35,
|
||||
"targets": "single",
|
||||
"baseHitChance": 0.85,
|
||||
"damageTable": {
|
||||
"lightning": 8,
|
||||
"physical": 8
|
||||
},
|
||||
"debuffNames": [
|
||||
{
|
||||
"name": "shocked",
|
||||
"chance": 0.5
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
75
src/lineage-json/item-route/arrows.json
Normal file
75
src/lineage-json/item-route/arrows.json
Normal file
@@ -0,0 +1,75 @@
|
||||
[
|
||||
{
|
||||
"name": "iron arrow",
|
||||
"baseValue": 2,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stackable": true,
|
||||
"stats": {
|
||||
"physicalDamage": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "steel arrow",
|
||||
"baseValue": 4,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stats": {
|
||||
"physicalDamage": 1.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "refined arrow",
|
||||
"baseValue": 8,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stats": {
|
||||
"physicalDamage": 2.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "barbed arrow",
|
||||
"baseValue": 15,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stats": {
|
||||
"physicalDamage": 3.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "great arrow",
|
||||
"baseValue": 20,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stats": {
|
||||
"physicalDamage": 4.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "explosive arrow",
|
||||
"baseValue": 40,
|
||||
"slot": "quiver",
|
||||
"icon": "Arrow",
|
||||
"stats": {
|
||||
"physicalDamage": 5.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 25
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
8
src/lineage-json/item-route/artifacts.json
Normal file
8
src/lineage-json/item-route/artifacts.json
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
{
|
||||
"name": "golden goblet",
|
||||
"icon": "Goblet",
|
||||
"baseValue": 5000
|
||||
}
|
||||
]
|
||||
|
||||
122
src/lineage-json/item-route/bodyArmor.json
Normal file
122
src/lineage-json/item-route/bodyArmor.json
Normal file
@@ -0,0 +1,122 @@
|
||||
[
|
||||
{
|
||||
"name": "cheap leather chestpiece",
|
||||
"baseValue": 400,
|
||||
"icon": "Leather_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 7.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leather chestpiece",
|
||||
"baseValue": 800,
|
||||
"icon": "Leather_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 10.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cheap iron chestpiece",
|
||||
"baseValue": 1500,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 15.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iron chestpiece",
|
||||
"baseValue": 2000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 20.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "steel chestpiece",
|
||||
"baseValue": 5000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 25.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "barbarian king armor",
|
||||
"baseValue": 10000,
|
||||
"icon": "Leather_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 20.0,
|
||||
"health": 50
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "knight's breastplate",
|
||||
"baseValue": 15000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 30.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"intelligence": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crusader's breastplate",
|
||||
"baseValue": 75000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 30.0,
|
||||
"health": 100,
|
||||
"mana": 100
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 25,
|
||||
"intelligence": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "soldier of fortune",
|
||||
"baseValue": 225000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 58.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 35
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "kingsman chestpiece",
|
||||
"baseValue": 550000,
|
||||
"icon": "Iron_Armor",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 50.0,
|
||||
"health": 250,
|
||||
"mana": 100
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 30,
|
||||
"intelligence": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
147
src/lineage-json/item-route/bows.json
Normal file
147
src/lineage-json/item-route/bows.json
Normal file
@@ -0,0 +1,147 @@
|
||||
[
|
||||
{
|
||||
"name": "short bow",
|
||||
"baseValue": 300,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"rooting shot"
|
||||
],
|
||||
"icon": "Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 5.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "recurve bow",
|
||||
"baseValue": 500,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"rapid shot"
|
||||
],
|
||||
"icon": "Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 7.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "long bow",
|
||||
"baseValue": 1000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"careful shot"
|
||||
],
|
||||
"icon": "Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 10.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 7
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "serpent bow",
|
||||
"baseValue": 5000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"poison shot"
|
||||
],
|
||||
"icon": "Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 12.5
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "great bow",
|
||||
"baseValue": 9500,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"overdraw"
|
||||
],
|
||||
"icon": "Great_Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 19
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "great serpent bow",
|
||||
"baseValue": 35000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"poison shot"
|
||||
],
|
||||
"icon": "Great_Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 22
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "harp bow",
|
||||
"baseValue": 75000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"rapid shot"
|
||||
],
|
||||
"icon": "Harp_Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 25
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "black bow",
|
||||
"baseValue": 150000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"seeking shot"
|
||||
],
|
||||
"icon": "Black_Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 29
|
||||
},
|
||||
"requirements": {
|
||||
"dexterity": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "hunter of bael",
|
||||
"baseValue": 450000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"shoot",
|
||||
"overdraw"
|
||||
],
|
||||
"icon": "Great_Bow",
|
||||
"stats": {
|
||||
"physicalDamage": 32
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 20,
|
||||
"dexterity": 20
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
192
src/lineage-json/item-route/foci.json
Normal file
192
src/lineage-json/item-route/foci.json
Normal file
@@ -0,0 +1,192 @@
|
||||
[
|
||||
{
|
||||
"name": "cheap focus",
|
||||
"icon": "Focus_1",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 25,
|
||||
"magicDamage": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 5
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "basic focus",
|
||||
"icon": "Focus_1",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 50,
|
||||
"magicDamage": 5
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 10
|
||||
},
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "cracked focus",
|
||||
"icon": "Focus_1",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"magicDamage": 15
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 15
|
||||
},
|
||||
"baseValue": 3000
|
||||
},
|
||||
{
|
||||
"name": "buzzing focus",
|
||||
"icon": "Focus_1",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"magicDamage": 10,
|
||||
"manaRegen": 1
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 15
|
||||
},
|
||||
"baseValue": 3500
|
||||
},
|
||||
{
|
||||
"name": "apprentice's focus",
|
||||
"icon": "Focus_2",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 75,
|
||||
"magicDamage": 12,
|
||||
"manaRegen": 1
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 18
|
||||
},
|
||||
"baseValue": 8000
|
||||
},
|
||||
{
|
||||
"name": "crystalline focus",
|
||||
"icon": "Focus_2",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 100,
|
||||
"magicDamage": 15
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 20
|
||||
},
|
||||
"baseValue": 12000
|
||||
},
|
||||
{
|
||||
"name": "resonating focus",
|
||||
"icon": "Focus_2",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"magicDamage": 18,
|
||||
"manaRegen": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 22
|
||||
},
|
||||
"baseValue": 15000
|
||||
},
|
||||
{
|
||||
"name": "mage's focus",
|
||||
"icon": "Focus_2",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 150,
|
||||
"magicDamage": 20,
|
||||
"manaRegen": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 25
|
||||
},
|
||||
"baseValue": 25000
|
||||
},
|
||||
{
|
||||
"name": "arcane focus",
|
||||
"icon": "Focus_3",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 200,
|
||||
"magicDamage": 25,
|
||||
"manaRegen": 3
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 30
|
||||
},
|
||||
"baseValue": 45000
|
||||
},
|
||||
{
|
||||
"name": "enchanted focus",
|
||||
"icon": "Focus_3",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 250,
|
||||
"magicDamage": 30,
|
||||
"manaRegen": 3
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 35
|
||||
},
|
||||
"baseValue": 75000
|
||||
},
|
||||
{
|
||||
"name": "sorcerer's focus",
|
||||
"icon": "Focus_3",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 300,
|
||||
"magicDamage": 35,
|
||||
"manaRegen": 4
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 40
|
||||
},
|
||||
"baseValue": 120000
|
||||
},
|
||||
{
|
||||
"name": "master's focus",
|
||||
"icon": "Focus_3",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 400,
|
||||
"magicDamage": 40,
|
||||
"manaRegen": 5
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 45
|
||||
},
|
||||
"baseValue": 180000
|
||||
},
|
||||
{
|
||||
"name": "archmagus focus",
|
||||
"icon": "Focus_4",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 500,
|
||||
"magicDamage": 45,
|
||||
"manaRegen": 6
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 50
|
||||
},
|
||||
"baseValue": 250000
|
||||
},
|
||||
{
|
||||
"name": "legendary focus",
|
||||
"icon": "Focus_4",
|
||||
"slot": "off-hand",
|
||||
"stats": {
|
||||
"mana": 600,
|
||||
"magicDamage": 50,
|
||||
"manaRegen": 7
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 55
|
||||
},
|
||||
"baseValue": 350000
|
||||
}
|
||||
]
|
||||
|
||||
129
src/lineage-json/item-route/hats.json
Normal file
129
src/lineage-json/item-route/hats.json
Normal file
@@ -0,0 +1,129 @@
|
||||
[
|
||||
{
|
||||
"name": "apprentice hood",
|
||||
"baseValue": 1000,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 3,
|
||||
"manaRegen": 1
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "adept hood",
|
||||
"baseValue": 2500,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 3,
|
||||
"mana": 20,
|
||||
"manaRegen": 1
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mage hood",
|
||||
"baseValue": 2500,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 5,
|
||||
"mana": 100
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gorgeous hood",
|
||||
"baseValue": 4500,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 5,
|
||||
"mana": 30,
|
||||
"manaRegen": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "expert hood",
|
||||
"baseValue": 10000,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 5,
|
||||
"mana": 50,
|
||||
"manaRegen": 4
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rouge magi's hood",
|
||||
"baseValue": 17500,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 8,
|
||||
"manaRegen": 8
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 5,
|
||||
"intelligence": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "war mage's cap",
|
||||
"baseValue": 65000,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 15,
|
||||
"mana": 40,
|
||||
"manaRegen": 5,
|
||||
"health": 40
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"intelligence": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ancient veil",
|
||||
"baseValue": 100000,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"mana": 200,
|
||||
"manaRegen": 10
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-mage's veil",
|
||||
"baseValue": 350000,
|
||||
"icon": "Wizard_Hat",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 8,
|
||||
"mana": 150,
|
||||
"health": 50,
|
||||
"manaRegen": 10
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 35
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
121
src/lineage-json/item-route/helmets.json
Normal file
121
src/lineage-json/item-route/helmets.json
Normal file
@@ -0,0 +1,121 @@
|
||||
[
|
||||
{
|
||||
"name": "feather",
|
||||
"baseValue": 100,
|
||||
"icon": "Feather",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 1.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "leather headgear",
|
||||
"baseValue": 500,
|
||||
"icon": "Leather_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 3.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cheap iron helmet",
|
||||
"baseValue": 1500,
|
||||
"icon": "Iron_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 5.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iron helmet",
|
||||
"baseValue": 2000,
|
||||
"icon": "Iron_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 8.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "steel helmet",
|
||||
"baseValue": 5000,
|
||||
"icon": "Iron_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 10.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "barbarian king headgear",
|
||||
"baseValue": 10000,
|
||||
"icon": "Leather_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 8.0,
|
||||
"health": 50
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "knight's helm",
|
||||
"baseValue": 15000,
|
||||
"icon": "Iron_Helmet",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 12.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crusader's helm",
|
||||
"baseValue": 75000,
|
||||
"icon": "Helm",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 15.0,
|
||||
"health": 100,
|
||||
"mana": 100
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 18,
|
||||
"intelligence": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "helm of fortune",
|
||||
"baseValue": 225000,
|
||||
"icon": "Helm",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 25.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "kingsman helm",
|
||||
"baseValue": 550000,
|
||||
"icon": "Helm",
|
||||
"slot": "head",
|
||||
"stats": {
|
||||
"armor": 22.0,
|
||||
"health": 250,
|
||||
"mana": 100
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 25,
|
||||
"intelligence": 10
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
18
src/lineage-json/item-route/ingredients.json
Normal file
18
src/lineage-json/item-route/ingredients.json
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"name": "bat wing",
|
||||
"icon": "Bat_Wing",
|
||||
"baseValue": 10
|
||||
},
|
||||
{
|
||||
"name": "rat tail",
|
||||
"icon": "Rat_Tail",
|
||||
"baseValue": 15
|
||||
},
|
||||
{
|
||||
"name": "ghostly residue",
|
||||
"icon": "Slime_Gel",
|
||||
"baseValue": 100
|
||||
}
|
||||
]
|
||||
|
||||
18
src/lineage-json/item-route/junk.json
Normal file
18
src/lineage-json/item-route/junk.json
Normal file
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"name": "patch of fur",
|
||||
"icon": "Patch_of_Fur",
|
||||
"baseValue": 5
|
||||
},
|
||||
{
|
||||
"name": "vampiric tooth",
|
||||
"icon": "Fang",
|
||||
"baseValue": 25
|
||||
},
|
||||
{
|
||||
"name": "chunk of flesh",
|
||||
"icon": "Chunk_of_Flesh",
|
||||
"baseValue": 40
|
||||
}
|
||||
]
|
||||
|
||||
308
src/lineage-json/item-route/melee.json
Normal file
308
src/lineage-json/item-route/melee.json
Normal file
@@ -0,0 +1,308 @@
|
||||
[
|
||||
{
|
||||
"name": "stick",
|
||||
"baseValue": 50,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"hit"
|
||||
],
|
||||
"icon": "Wood_Log",
|
||||
"stats": {
|
||||
"physicalDamage": 2.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "big stick",
|
||||
"baseValue": 75,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"hit"
|
||||
],
|
||||
"icon": "Wood_Log",
|
||||
"stats": {
|
||||
"physicalDamage": 4.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "torch",
|
||||
"baseValue": 300,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"torch stab"
|
||||
],
|
||||
"icon": "Torch",
|
||||
"stats": {
|
||||
"physicalDamage": 1.5,
|
||||
"fireDamage": 1.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dagger",
|
||||
"baseValue": 400,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"stab"
|
||||
],
|
||||
"icon": "Knife",
|
||||
"stats": {
|
||||
"physicalDamage": 4.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shortsword",
|
||||
"baseValue": 1200,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash"
|
||||
],
|
||||
"icon": "Iron_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 7.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mace",
|
||||
"baseValue": 1100,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"crushing blow"
|
||||
],
|
||||
"icon": "Hammer",
|
||||
"stats": {
|
||||
"physicalDamage": 6.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rat-smasher",
|
||||
"baseValue": 2000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"crushing blow"
|
||||
],
|
||||
"icon": "Hammer",
|
||||
"stats": {
|
||||
"physicalDamage": 10.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "longsword",
|
||||
"baseValue": 10000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash"
|
||||
],
|
||||
"icon": "Iron_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 10.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 8,
|
||||
"dexterity": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "bastard sword",
|
||||
"baseValue": 15000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Iron_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 20.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "elegant blade",
|
||||
"baseValue": 20000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash"
|
||||
],
|
||||
"icon": "Silver_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 16.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "axe",
|
||||
"baseValue": 25000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Axe",
|
||||
"stats": {
|
||||
"physicalDamage": 20.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "zweihänder",
|
||||
"baseValue": 34000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Iron_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 29.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "grotesque dagger",
|
||||
"baseValue": 38000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"serrate"
|
||||
],
|
||||
"icon": "Knife",
|
||||
"stats": {
|
||||
"physicalDamage": 18.0,
|
||||
"poisonDamage": 4.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"dexterity": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "greataxe",
|
||||
"baseValue": 65000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"hack"
|
||||
],
|
||||
"icon": "Axe",
|
||||
"stats": {
|
||||
"physicalDamage": 33.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "greatsword",
|
||||
"baseValue": 65000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Iron_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 37.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "royal longsword",
|
||||
"baseValue": 85000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Golden_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 30.0,
|
||||
"magicDamage": 5.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 25,
|
||||
"dexterity": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "barbarian war axe",
|
||||
"baseValue": 150000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"hack"
|
||||
],
|
||||
"icon": "Axe",
|
||||
"stats": {
|
||||
"physicalDamage": 30.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 33
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "knight's greatsword",
|
||||
"baseValue": 225000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Golden_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 35.5
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 32
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crusader's longsword",
|
||||
"baseValue": 310000,
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"slash",
|
||||
"cleave"
|
||||
],
|
||||
"icon": "Golden_Sword",
|
||||
"stats": {
|
||||
"physicalDamage": 27.0,
|
||||
"holyDamage": 6.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 30,
|
||||
"dexterity": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "crusader's war hammer",
|
||||
"baseValue": 310000,
|
||||
"slot": "two-hand",
|
||||
"attacks": [
|
||||
"crushing blow"
|
||||
],
|
||||
"icon": "Golden_Hammer",
|
||||
"stats": {
|
||||
"physicalDamage": 45.0
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 45
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
120
src/lineage-json/item-route/poison.json
Normal file
120
src/lineage-json/item-route/poison.json
Normal file
@@ -0,0 +1,120 @@
|
||||
[
|
||||
{
|
||||
"name": "basic wounding poison",
|
||||
"icon": "Green_Potion",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 10,
|
||||
"max": 30
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "strong wounding poison",
|
||||
"icon": "Green_Potion_2",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 50,
|
||||
"max": 75
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "ultimate wounding poison",
|
||||
"icon": "Green_Potion_3",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 125,
|
||||
"max": 175
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "basic lethargic poison",
|
||||
"icon": "Green_Potion",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 10,
|
||||
"max": 30
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "strong lethargic poison",
|
||||
"icon": "Green_Potion_2",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 50,
|
||||
"max": 75
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "ultimate lethargic poison",
|
||||
"icon": "Green_Potion_3",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 125,
|
||||
"max": 175
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "basic madness poison",
|
||||
"icon": "Green_Potion",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 10,
|
||||
"max": 30
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "strong madness poison",
|
||||
"icon": "Green_Potion_2",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 50,
|
||||
"max": 75
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 2500
|
||||
},
|
||||
{
|
||||
"name": "ultimate madness poison",
|
||||
"icon": "Green_Potion_3",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 125,
|
||||
"max": 175
|
||||
},
|
||||
"isPoison": true
|
||||
},
|
||||
"baseValue": 10000
|
||||
}
|
||||
]
|
||||
|
||||
198
src/lineage-json/item-route/potions.json
Normal file
198
src/lineage-json/item-route/potions.json
Normal file
@@ -0,0 +1,198 @@
|
||||
[
|
||||
{
|
||||
"name": "basic healing potion",
|
||||
"icon": "Red_Potion",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 20,
|
||||
"max": 50
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 100
|
||||
},
|
||||
{
|
||||
"name": "moderate healing potion",
|
||||
"icon": "Red_Potion",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 40,
|
||||
"max": 80
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "strong healing potion",
|
||||
"icon": "Red_Potion_2",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 70,
|
||||
"max": 100
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 2000
|
||||
},
|
||||
{
|
||||
"name": "intense healing potion",
|
||||
"icon": "Red_Potion_2",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 100,
|
||||
"max": 180
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 4000
|
||||
},
|
||||
{
|
||||
"name": "extreme healing potion",
|
||||
"icon": "Red_Potion_3",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 150,
|
||||
"max": 300
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 7500
|
||||
},
|
||||
{
|
||||
"name": "ultimate healing potion",
|
||||
"icon": "Red_Potion_3",
|
||||
"effect": {
|
||||
"stat": "health",
|
||||
"amount": {
|
||||
"min": 250,
|
||||
"max": 500
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "basic mana potion",
|
||||
"icon": "Blue_Potion",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 20,
|
||||
"max": 50
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 100
|
||||
},
|
||||
{
|
||||
"name": "moderate mana potion",
|
||||
"icon": "Blue_Potion",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 40,
|
||||
"max": 80
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 500
|
||||
},
|
||||
{
|
||||
"name": "strong mana potion",
|
||||
"icon": "Blue_Potion_2",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 70,
|
||||
"max": 100
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 2000
|
||||
},
|
||||
{
|
||||
"name": "intense mana potion",
|
||||
"icon": "Blue_Potion_2",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 100,
|
||||
"max": 180
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 4000
|
||||
},
|
||||
{
|
||||
"name": "extreme mana potion",
|
||||
"icon": "Blue_Potion_3",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 150,
|
||||
"max": 300
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 7500
|
||||
},
|
||||
{
|
||||
"name": "ultimate mana potion",
|
||||
"icon": "Blue_Potion_3",
|
||||
"effect": {
|
||||
"stat": "mana",
|
||||
"amount": {
|
||||
"min": 250,
|
||||
"max": 500
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 10000
|
||||
},
|
||||
{
|
||||
"name": "basic calming potion",
|
||||
"icon": "Purple_Potion",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 20,
|
||||
"max": 35
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 100
|
||||
},
|
||||
{
|
||||
"name": "strong calming potion",
|
||||
"icon": "Purple_Potion_2",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 50,
|
||||
"max": 75
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 2000
|
||||
},
|
||||
{
|
||||
"name": "ultimate calming potion",
|
||||
"icon": "Purple_Potion_3",
|
||||
"effect": {
|
||||
"stat": "sanity",
|
||||
"amount": {
|
||||
"min": 100,
|
||||
"max": 150
|
||||
},
|
||||
"isPoison": false
|
||||
},
|
||||
"baseValue": 10000
|
||||
}
|
||||
]
|
||||
|
||||
471
src/lineage-json/item-route/prefix.json
Normal file
471
src/lineage-json/item-route/prefix.json
Normal file
@@ -0,0 +1,471 @@
|
||||
[
|
||||
{
|
||||
"name": {
|
||||
"5": "healthy",
|
||||
"4": "hearty",
|
||||
"3": "hearty",
|
||||
"2": "vital",
|
||||
"1": "invigorating"
|
||||
},
|
||||
"modifier": {
|
||||
"health": [
|
||||
{
|
||||
"5": {
|
||||
"min": 10,
|
||||
"max": 14
|
||||
},
|
||||
"4": {
|
||||
"min": 15,
|
||||
"max": 19
|
||||
},
|
||||
"3": {
|
||||
"min": 20,
|
||||
"max": 24
|
||||
},
|
||||
"2": {
|
||||
"min": 25,
|
||||
"max": 29
|
||||
},
|
||||
"1": {
|
||||
"min": 30,
|
||||
"max": 35
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 5
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"5": "sturdy",
|
||||
"4": "robust",
|
||||
"3": "robust",
|
||||
"2": "vigorous",
|
||||
"1": "flourishing"
|
||||
},
|
||||
"modifier": {
|
||||
"health": [
|
||||
{
|
||||
"5": {
|
||||
"min": 8,
|
||||
"max": 11
|
||||
},
|
||||
"4": {
|
||||
"min": 12,
|
||||
"max": 15
|
||||
},
|
||||
"3": {
|
||||
"min": 16,
|
||||
"max": 19
|
||||
},
|
||||
"2": {
|
||||
"min": 20,
|
||||
"max": 23
|
||||
},
|
||||
"1": {
|
||||
"min": 24,
|
||||
"max": 28
|
||||
}
|
||||
}
|
||||
],
|
||||
"healthRegen": [
|
||||
{
|
||||
"5": {
|
||||
"min": 1,
|
||||
"max": 1
|
||||
},
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 2
|
||||
},
|
||||
"2": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"1": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 5
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "sage",
|
||||
"3": "wise",
|
||||
"2": "wise",
|
||||
"1": "enlightened"
|
||||
},
|
||||
"modifier": {
|
||||
"mana": [
|
||||
{
|
||||
"4": {
|
||||
"min": 8,
|
||||
"max": 11
|
||||
},
|
||||
"3": {
|
||||
"min": 12,
|
||||
"max": 15
|
||||
},
|
||||
"2": {
|
||||
"min": 16,
|
||||
"max": 19
|
||||
},
|
||||
"1": {
|
||||
"min": 20,
|
||||
"max": 25
|
||||
}
|
||||
}
|
||||
],
|
||||
"intelligence": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "balanced",
|
||||
"2": "stable",
|
||||
"1": "harmonious"
|
||||
},
|
||||
"modifier": {
|
||||
"sanity": [
|
||||
{
|
||||
"3": {
|
||||
"min": 10,
|
||||
"max": 14
|
||||
},
|
||||
"2": {
|
||||
"min": 15,
|
||||
"max": 19
|
||||
},
|
||||
"1": {
|
||||
"min": 20,
|
||||
"max": 25
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "energetic",
|
||||
"3": "vigorous",
|
||||
"2": "vigorous",
|
||||
"1": "revitalizing"
|
||||
},
|
||||
"modifier": {
|
||||
"healthRegen": [
|
||||
{
|
||||
"4": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"3": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"2": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
},
|
||||
"1": {
|
||||
"min": 5,
|
||||
"max": 6
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "focused",
|
||||
"2": "concentrated",
|
||||
"1": "meditative"
|
||||
},
|
||||
"modifier": {
|
||||
"manaRegen": [
|
||||
{
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "strong",
|
||||
"2": "mighty",
|
||||
"1": "herculean"
|
||||
},
|
||||
"modifier": {
|
||||
"strength": [
|
||||
{
|
||||
"3": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"2": {
|
||||
"min": 5,
|
||||
"max": 6
|
||||
},
|
||||
"1": {
|
||||
"min": 7,
|
||||
"max": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "nimble",
|
||||
"2": "agile",
|
||||
"1": "acrobatic"
|
||||
},
|
||||
"modifier": {
|
||||
"dexterity": [
|
||||
{
|
||||
"3": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"2": {
|
||||
"min": 5,
|
||||
"max": 6
|
||||
},
|
||||
"1": {
|
||||
"min": 7,
|
||||
"max": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "protective",
|
||||
"3": "fortified",
|
||||
"2": "fortified",
|
||||
"1": "impenetrable"
|
||||
},
|
||||
"modifier": {
|
||||
"armorAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 5,
|
||||
"max": 7
|
||||
},
|
||||
"3": {
|
||||
"min": 8,
|
||||
"max": 10
|
||||
},
|
||||
"2": {
|
||||
"min": 11,
|
||||
"max": 13
|
||||
},
|
||||
"1": {
|
||||
"min": 14,
|
||||
"max": 16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "tough",
|
||||
"3": "tempered",
|
||||
"2": "tempered",
|
||||
"1": "unyielding"
|
||||
},
|
||||
"modifier": {
|
||||
"armorAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"3": {
|
||||
"min": 5,
|
||||
"max": 6
|
||||
},
|
||||
"2": {
|
||||
"min": 7,
|
||||
"max": 8
|
||||
},
|
||||
"1": {
|
||||
"min": 9,
|
||||
"max": 10
|
||||
}
|
||||
}
|
||||
],
|
||||
"health": [
|
||||
{
|
||||
"4": {
|
||||
"min": 4,
|
||||
"max": 6
|
||||
},
|
||||
"3": {
|
||||
"min": 7,
|
||||
"max": 9
|
||||
},
|
||||
"2": {
|
||||
"min": 10,
|
||||
"max": 12
|
||||
},
|
||||
"1": {
|
||||
"min": 13,
|
||||
"max": 15
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "flameward",
|
||||
"2": "flameproof",
|
||||
"1": "infernoshield"
|
||||
},
|
||||
"modifier": {
|
||||
"fireResistance": [
|
||||
{
|
||||
"3": {
|
||||
"min": 0.08,
|
||||
"max": 0.10
|
||||
},
|
||||
"2": {
|
||||
"min": 0.11,
|
||||
"max": 0.13
|
||||
},
|
||||
"1": {
|
||||
"min": 0.14,
|
||||
"max": 0.16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "frostward",
|
||||
"2": "frostproof",
|
||||
"1": "glacialshield"
|
||||
},
|
||||
"modifier": {
|
||||
"coldResistance": [
|
||||
{
|
||||
"3": {
|
||||
"min": 0.08,
|
||||
"max": 0.10
|
||||
},
|
||||
"2": {
|
||||
"min": 0.11,
|
||||
"max": 0.13
|
||||
},
|
||||
"1": {
|
||||
"min": 0.14,
|
||||
"max": 0.16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "stormward",
|
||||
"2": "stormproof",
|
||||
"1": "thundershield"
|
||||
},
|
||||
"modifier": {
|
||||
"lightningResistance": [
|
||||
{
|
||||
"3": {
|
||||
"min": 0.8,
|
||||
"max": 0.10
|
||||
},
|
||||
"2": {
|
||||
"min": 0.11,
|
||||
"max": 0.13
|
||||
},
|
||||
"1": {
|
||||
"min": 0.14,
|
||||
"max": 0.16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"3": "toxic",
|
||||
"2": "antitoxin",
|
||||
"1": "venomshield"
|
||||
},
|
||||
"modifier": {
|
||||
"poisonResistance": [
|
||||
{
|
||||
"3": {
|
||||
"min": 0.08,
|
||||
"max": 0.10
|
||||
},
|
||||
"2": {
|
||||
"min": 0.11,
|
||||
"max": 0.13
|
||||
},
|
||||
"1": {
|
||||
"min": 0.14,
|
||||
"max": 0.16
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 3
|
||||
}
|
||||
]
|
||||
|
||||
141
src/lineage-json/item-route/robes.json
Normal file
141
src/lineage-json/item-route/robes.json
Normal file
@@ -0,0 +1,141 @@
|
||||
[
|
||||
{
|
||||
"name": "cloth robes",
|
||||
"baseValue": 200,
|
||||
"icon": "Robes_1",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 4,
|
||||
"mana": 15,
|
||||
"manaRegen": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "apprentice robes",
|
||||
"baseValue": 1500,
|
||||
"icon": "Robes_1",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 6,
|
||||
"mana": 25,
|
||||
"manaRegen": 0
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "adept robes",
|
||||
"baseValue": 2500,
|
||||
"icon": "Robes_1",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 8,
|
||||
"mana": 50,
|
||||
"manaRegen": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mage robes",
|
||||
"baseValue": 2500,
|
||||
"icon": "Robes_2",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 8,
|
||||
"mana": 100,
|
||||
"manaRegen": 0
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "gorgeous robes",
|
||||
"baseValue": 6500,
|
||||
"icon": "Robes_2",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 10,
|
||||
"mana": 100,
|
||||
"manaRegen": 2
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "expert robes",
|
||||
"baseValue": 25000,
|
||||
"icon": "Robes_2",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 10,
|
||||
"mana": 150,
|
||||
"manaRegen": 5
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "rouge magi's vestment",
|
||||
"baseValue": 47500,
|
||||
"icon": "Robes_3",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 16,
|
||||
"manaRegen": 12
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 5,
|
||||
"intelligence": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "war mage's vestment",
|
||||
"baseValue": 95000,
|
||||
"icon": "Robes_3",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 28,
|
||||
"mana": 100,
|
||||
"manaRegen": 8,
|
||||
"health": 100
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10,
|
||||
"intelligence": 30
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ancient silks",
|
||||
"baseValue": 200000,
|
||||
"icon": "Robes_3",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"mana": 400,
|
||||
"manaRegen": 20
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 40
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "arch-mage's robes",
|
||||
"baseValue": 450000,
|
||||
"icon": "Robes_3",
|
||||
"slot": "body",
|
||||
"stats": {
|
||||
"armor": 25,
|
||||
"mana": 350,
|
||||
"manaRegen": 20
|
||||
},
|
||||
"requirements": {
|
||||
"intelligence": 50
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
114
src/lineage-json/item-route/shields.json
Normal file
114
src/lineage-json/item-route/shields.json
Normal file
@@ -0,0 +1,114 @@
|
||||
[
|
||||
{
|
||||
"name": "block of wood",
|
||||
"baseValue": 100,
|
||||
"icon": "Wooden_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 4.0,
|
||||
"blockChance": 0.035
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cheap buckler",
|
||||
"baseValue": 500,
|
||||
"icon": "Wooden_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 6.0,
|
||||
"blockChance": 0.05
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "block of iron",
|
||||
"baseValue": 1000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 9.0,
|
||||
"blockChance": 0.035
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "iron shield",
|
||||
"baseValue": 7000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 11.0,
|
||||
"blockChance": 0.05
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "kite shield",
|
||||
"baseValue": 14000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 10.0,
|
||||
"blockChance": 0.07
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pavise",
|
||||
"baseValue": 32000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 14.0,
|
||||
"blockChance": 0.10
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 15
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "great shield",
|
||||
"baseValue": 80000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 20.0,
|
||||
"blockChance": 0.06
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 22
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "royal great shield",
|
||||
"baseValue": 120000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 30.0,
|
||||
"blockChance": 0.07
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shield of glory",
|
||||
"baseValue": 350000,
|
||||
"icon": "Iron_Shield",
|
||||
"slot": "one-hand",
|
||||
"stats": {
|
||||
"armor": 40.0,
|
||||
"blockChance": 0.07
|
||||
},
|
||||
"requirements": {
|
||||
"strength": 35
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
16
src/lineage-json/item-route/staves.json
Normal file
16
src/lineage-json/item-route/staves.json
Normal file
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"name": "Goblin Totem",
|
||||
"baseValue": 5000,
|
||||
"icon": "Goblin_Staff",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"bonk",
|
||||
"spark"
|
||||
],
|
||||
"stats": {
|
||||
"physicalDamage": 8.0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
21
src/lineage-json/item-route/storyItems.json
Normal file
21
src/lineage-json/item-route/storyItems.json
Normal file
@@ -0,0 +1,21 @@
|
||||
[
|
||||
{
|
||||
"name": "the deed to the whispering raven inn",
|
||||
"icon": "Scroll",
|
||||
"description": "<Font>Cursive</Font>**Holding this deed means The Whispering Raven Inn is yours, but you will need to repair the property before it can serve patrons**\n*The parchment is stained with dark splotches, its edges frayed and torn. On the back on the deed there are scribles The handwriting becomes increasingly erratic as it progresses.*\n\nTo those who would judge me,\n\nI, Alaric Shadowmere, once proprietor of the Whispering Raven Inn, pen this final testament. Let it serve as both confession and vindication for the deeds that have brought me to this wretched state.\n\nFor years, I welcomed weary travelers, offering respite from the horrors that roam our blighted lands. But with each passing season, I bore witness to the futility of it all. The weak perish, the strong exploit, and death claims us all in the end.\n\nIt was then that the whispers began. The ancient tomes hidden beneath the floorboards of my cellar spoke of power beyond mortal ken. They promised a way to conquer death itself, to build an army that would never tire, never falter.\n\nAnd so, I began my great work.\n\nEach patron who crossed my threshold became more than a guest – they became raw material for my grand design. Their flesh, their bones, their very essence – all repurposed in service of a greater cause.\n\nDo you not see the beauty in it? The drunkard who squandered his life now stands eternal guard. The abusive merchant now toils without rest or reward. I have given them purpose beyond their petty lives!\n\n<em>But the FOOLS outside do not understand!</em>\n\nThey call me <em>monster, madman, murderer.</em> They cannot comprehend the magnitude of my vision.\n\nAs I write this, I hear them coming. The villagers, the so-called heroes, all clamoring for my head. Let them come. My children – my beautiful, rotting children – will greet them.\n\nAnd should I fall, know this: Death is but a doorway. I have peered beyond its threshold, and I fear it no longer. In time, you too will understand the gift I offered this miserable world.\n\nMay He embrace us all.\n\n*The signature at the bottom is a smeared, illegible scrawl*",
|
||||
"baseValue": -1
|
||||
},
|
||||
{
|
||||
"name": "head of goblin shaman",
|
||||
"icon": "Skull",
|
||||
"description": "*Stick it on a spike to ward off other Goblin tribes, and confer safety to a trade route*\n\n",
|
||||
"baseValue": -1
|
||||
},
|
||||
{
|
||||
"name": "broken seal contract",
|
||||
"icon": "Paper",
|
||||
"description": "<Font>Cursive</Font>*A weathered piece of parchment sealed with black wax bearing a bleeding sun. The edges are singed as if exposed to intense heat.*\n\nBy acceptance of payment in gold, the undersigned hereby commits to the procurement and delivery of specimens matching the following criteria:\n\n- Aged 12 and over.\n\n- Weight of 7.5 stone or greater.\n\nHE requires these specimens intact and breathing. The method of acquisition is at your discretion, though discretion itself is paramount. Those who draw undue attention will find their own names added to HIS ledger.\n\nPayment will be rendered upon delivery to the Blood Eye Gate. Additional compensation will be provided for specimens of exceptional quality.\n\nFailure to deliver will result in the forfeiture of not only payment but also that which you hold most precious.\n\n*The signature appears to be written in a script that hurts the eyes to look upon directly*",
|
||||
"baseValue": -1
|
||||
}
|
||||
]
|
||||
|
||||
413
src/lineage-json/item-route/suffix.json
Normal file
413
src/lineage-json/item-route/suffix.json
Normal file
@@ -0,0 +1,413 @@
|
||||
[
|
||||
{
|
||||
"name": {
|
||||
"4": "soldier",
|
||||
"3": "warrior",
|
||||
"2": "champion",
|
||||
"1": "hero"
|
||||
},
|
||||
"modifier": {
|
||||
"physicalDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 6,
|
||||
"max": 8
|
||||
},
|
||||
"3": {
|
||||
"min": 9,
|
||||
"max": 11
|
||||
},
|
||||
"2": {
|
||||
"min": 12,
|
||||
"max": 14
|
||||
},
|
||||
"1": {
|
||||
"min": 15,
|
||||
"max": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "smoldering",
|
||||
"3": "burning",
|
||||
"2": "scorching",
|
||||
"1": "infernal"
|
||||
},
|
||||
"modifier": {
|
||||
"fireDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 6,
|
||||
"max": 8
|
||||
},
|
||||
"3": {
|
||||
"min": 9,
|
||||
"max": 11
|
||||
},
|
||||
"2": {
|
||||
"min": 12,
|
||||
"max": 14
|
||||
},
|
||||
"1": {
|
||||
"min": 15,
|
||||
"max": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "chilled",
|
||||
"3": "frozen",
|
||||
"2": "glacier",
|
||||
"1": "arctic"
|
||||
},
|
||||
"modifier": {
|
||||
"coldDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 6,
|
||||
"max": 8
|
||||
},
|
||||
"3": {
|
||||
"min": 9,
|
||||
"max": 11
|
||||
},
|
||||
"2": {
|
||||
"min": 12,
|
||||
"max": 14
|
||||
},
|
||||
"1": {
|
||||
"min": 15,
|
||||
"max": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "static",
|
||||
"3": "shocked",
|
||||
"2": "electrified",
|
||||
"1": "thunderous"
|
||||
},
|
||||
"modifier": {
|
||||
"lightningDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 6,
|
||||
"max": 8
|
||||
},
|
||||
"3": {
|
||||
"min": 9,
|
||||
"max": 11
|
||||
},
|
||||
"2": {
|
||||
"min": 12,
|
||||
"max": 14
|
||||
},
|
||||
"1": {
|
||||
"min": 15,
|
||||
"max": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "noxious",
|
||||
"3": "venomous",
|
||||
"2": "virulent",
|
||||
"1": "pestilent"
|
||||
},
|
||||
"modifier": {
|
||||
"poisonDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 6,
|
||||
"max": 8
|
||||
},
|
||||
"3": {
|
||||
"min": 9,
|
||||
"max": 11
|
||||
},
|
||||
"2": {
|
||||
"min": 12,
|
||||
"max": 14
|
||||
},
|
||||
"1": {
|
||||
"min": 15,
|
||||
"max": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "challenger",
|
||||
"3": "gladiator",
|
||||
"2": "marauder",
|
||||
"1": "conqueror"
|
||||
},
|
||||
"modifier": {
|
||||
"physicalDamageMultiplier": [
|
||||
{
|
||||
"4": {
|
||||
"min": 0.05,
|
||||
"max": 0.08
|
||||
},
|
||||
"3": {
|
||||
"min": 0.09,
|
||||
"max": 0.12
|
||||
},
|
||||
"2": {
|
||||
"min": 0.13,
|
||||
"max": 0.16
|
||||
},
|
||||
"1": {
|
||||
"min": 0.17,
|
||||
"max": 0.20
|
||||
}
|
||||
}
|
||||
],
|
||||
"strength": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 1
|
||||
},
|
||||
"3": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"2": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"1": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "imp",
|
||||
"3": "fiend",
|
||||
"2": "demon",
|
||||
"1": "devil"
|
||||
},
|
||||
"modifier": {
|
||||
"fireDamageMultiplier": [
|
||||
{
|
||||
"4": {
|
||||
"min": 0.05,
|
||||
"max": 0.08
|
||||
},
|
||||
"3": {
|
||||
"min": 0.09,
|
||||
"max": 0.12
|
||||
},
|
||||
"2": {
|
||||
"min": 0.13,
|
||||
"max": 0.16
|
||||
},
|
||||
"1": {
|
||||
"min": 0.17,
|
||||
"max": 0.20
|
||||
}
|
||||
}
|
||||
],
|
||||
"fireDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "chilly",
|
||||
"3": "frigid",
|
||||
"2": "frozen",
|
||||
"1": "arctic"
|
||||
},
|
||||
"modifier": {
|
||||
"coldDamageMultiplier": [
|
||||
{
|
||||
"4": {
|
||||
"min": 0.05,
|
||||
"max": 0.08
|
||||
},
|
||||
"3": {
|
||||
"min": 0.09,
|
||||
"max": 0.12
|
||||
},
|
||||
"2": {
|
||||
"min": 0.13,
|
||||
"max": 0.16
|
||||
},
|
||||
"1": {
|
||||
"min": 0.17,
|
||||
"max": 0.20
|
||||
}
|
||||
}
|
||||
],
|
||||
"coldDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "charged",
|
||||
"3": "arcing",
|
||||
"2": "thunderous",
|
||||
"1": "superconducting"
|
||||
},
|
||||
"modifier": {
|
||||
"lightningDamageMultiplier": [
|
||||
{
|
||||
"4": {
|
||||
"min": 0.05,
|
||||
"max": 0.08
|
||||
},
|
||||
"3": {
|
||||
"min": 0.09,
|
||||
"max": 0.12
|
||||
},
|
||||
"2": {
|
||||
"min": 0.13,
|
||||
"max": 0.16
|
||||
},
|
||||
"1": {
|
||||
"min": 0.17,
|
||||
"max": 0.20
|
||||
}
|
||||
}
|
||||
],
|
||||
"lightningDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"4": "toxic",
|
||||
"3": "virulent",
|
||||
"2": "malignant",
|
||||
"1": "plague-bearer"
|
||||
},
|
||||
"modifier": {
|
||||
"poisonDamageMultiplier": [
|
||||
{
|
||||
"4": {
|
||||
"min": 0.05,
|
||||
"max": 0.08
|
||||
},
|
||||
"3": {
|
||||
"min": 0.09,
|
||||
"max": 0.12
|
||||
},
|
||||
"2": {
|
||||
"min": 0.13,
|
||||
"max": 0.16
|
||||
},
|
||||
"1": {
|
||||
"min": 0.17,
|
||||
"max": 0.20
|
||||
}
|
||||
}
|
||||
],
|
||||
"poisonDamageAdded": [
|
||||
{
|
||||
"4": {
|
||||
"min": 1,
|
||||
"max": 2
|
||||
},
|
||||
"3": {
|
||||
"min": 2,
|
||||
"max": 3
|
||||
},
|
||||
"2": {
|
||||
"min": 3,
|
||||
"max": 4
|
||||
},
|
||||
"1": {
|
||||
"min": 4,
|
||||
"max": 5
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"tiers": 4
|
||||
}
|
||||
]
|
||||
|
||||
244
src/lineage-json/item-route/wands.json
Normal file
244
src/lineage-json/item-route/wands.json
Normal file
@@ -0,0 +1,244 @@
|
||||
[
|
||||
{
|
||||
"name": "Apprentice Wand",
|
||||
"baseValue": 1000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 5.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Scorching Wand",
|
||||
"baseValue": 5000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"fireDamage": 8.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Frozen Wand",
|
||||
"baseValue": 12000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"coldDamage": 12.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of the Prodigy",
|
||||
"baseValue": 18000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 18.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Adept Wand",
|
||||
"baseValue": 22000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 20.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of the Inferno",
|
||||
"baseValue": 26000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"fireDamage": 23.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Enchanted Wand",
|
||||
"baseValue": 31000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 27.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of Blizzards",
|
||||
"baseValue": 40000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"coldDamage": 31.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Expert Wand",
|
||||
"baseValue": 48000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 34.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of Decay",
|
||||
"baseValue": 65000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"poisonDamage": 38.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Master's Wand",
|
||||
"baseValue": 84000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 42.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Ethereal Wand",
|
||||
"baseValue": 121000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 45.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Celestial Wand",
|
||||
"baseValue": 145000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"magicDamage": 48.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of Destiny",
|
||||
"baseValue": 185000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"holyDamage": 52.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of Misfortune",
|
||||
"baseValue": 245000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"poisonDamage": 55.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Light's End",
|
||||
"baseValue": 285000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"lightningDamage": 58.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Wand of the Forgotten",
|
||||
"baseValue": 335000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"physicalDamage": 60.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Divine Wand",
|
||||
"baseValue": 410000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"holyDamage": 62.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Death Ray",
|
||||
"baseValue": 520000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"poisonDamage": 65.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Finger of God",
|
||||
"baseValue": 750000,
|
||||
"icon": "Magic_Wand",
|
||||
"slot": "one-hand",
|
||||
"attacks": [
|
||||
"cast"
|
||||
],
|
||||
"stats": {
|
||||
"holyDamage": 50.0,
|
||||
"magicDamage": 20.0
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
224
src/lineage-json/misc-route/activities.json
Normal file
224
src/lineage-json/misc-route/activities.json
Normal file
@@ -0,0 +1,224 @@
|
||||
[
|
||||
{
|
||||
"name": "walk in the Enchanted Forest",
|
||||
"cost": 0,
|
||||
"alone": {
|
||||
"meetingSomeone": 0.15,
|
||||
"nothingHappens": 0.25,
|
||||
"randomGood": 0.40,
|
||||
"randomBad": 0.20
|
||||
},
|
||||
"dateCooldown": 5,
|
||||
"date": {
|
||||
"increaseAffection": 0.85,
|
||||
"increaseAffectionRange": {
|
||||
"min": 1,
|
||||
"max": 10
|
||||
},
|
||||
"decreaseAffection": 0.15,
|
||||
"decreaseAffectionRange": {
|
||||
"min": 1,
|
||||
"max": 5
|
||||
}
|
||||
},
|
||||
"randomBad": [
|
||||
{
|
||||
"name": "Mugged!",
|
||||
"buyOff": {
|
||||
"price": 300
|
||||
},
|
||||
"dungeonTitle": "Enchanted Forest",
|
||||
"fight": {
|
||||
"enemies": [
|
||||
{
|
||||
"name": "bandit",
|
||||
"image": "bandit_light",
|
||||
"scaler": 1,
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"randomGood": [
|
||||
{
|
||||
"name": "Found a gold pouch!",
|
||||
"effect": {
|
||||
"gold": 50
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Had a beautiful restorative walk",
|
||||
"effect": {
|
||||
"healthRestore": 25,
|
||||
"sanityRestore": 25
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "go to a Library",
|
||||
"cost": 0,
|
||||
"alone": {
|
||||
"meetingSomeone": 0.40,
|
||||
"nothingHappens": 0.40,
|
||||
"randomGood": 0.10,
|
||||
"randomBad": 0.10
|
||||
},
|
||||
"dateCooldown": 10,
|
||||
"date": {
|
||||
"increaseAffection": 0.85,
|
||||
"increaseAffectionRange": {
|
||||
"min": 3,
|
||||
"max": 7
|
||||
},
|
||||
"decreaseAffection": 0.15,
|
||||
"decreaseAffectionRange": {
|
||||
"min": 1,
|
||||
"max": 4
|
||||
}
|
||||
},
|
||||
"randomBad": [
|
||||
{
|
||||
"name": "Read a disturbing book",
|
||||
"effect": {
|
||||
"sanityDamage": 25
|
||||
}
|
||||
}
|
||||
],
|
||||
"randomGood": [
|
||||
{
|
||||
"name": "Read from your favorite author",
|
||||
"effect": {
|
||||
"sanityRestore": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Found a gold pouch!",
|
||||
"effect": {
|
||||
"gold": 25
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "go to the Pub",
|
||||
"cost": 25,
|
||||
"alone": {
|
||||
"meetingSomeone": 0.30,
|
||||
"nothingHappens": 0.20,
|
||||
"randomGood": 0.15,
|
||||
"randomBad": 0.35
|
||||
},
|
||||
"dateCooldown": 10,
|
||||
"date": {
|
||||
"increaseAffection": 0.80,
|
||||
"increaseAffectionRange": {
|
||||
"min": 5,
|
||||
"max": 15
|
||||
},
|
||||
"decreaseAffection": 0.20,
|
||||
"decreaseAffectionRange": {
|
||||
"min": 3,
|
||||
"max": 10
|
||||
}
|
||||
},
|
||||
"randomBad": [
|
||||
{
|
||||
"name": "Bar Fight",
|
||||
"dungeonTitle": "Local Pub",
|
||||
"fight": {
|
||||
"enemies": [
|
||||
{
|
||||
"name": "bandit heavy",
|
||||
"image": "bandit_heavy",
|
||||
"scaler": 1,
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"randomGood": [
|
||||
{
|
||||
"name": "Free Round",
|
||||
"effect": {
|
||||
"gold": 25,
|
||||
"sanityRestore": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Found a gold pouch!",
|
||||
"effect": {
|
||||
"gold": 75
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "go to a Festival",
|
||||
"cost": 50,
|
||||
"alone": {
|
||||
"meetingSomeone": 0.40,
|
||||
"nothingHappens": 0.40,
|
||||
"randomGood": 0.10,
|
||||
"randomBad": 0.10
|
||||
},
|
||||
"dateCooldown": 15,
|
||||
"date": {
|
||||
"increaseAffection": 0.85,
|
||||
"increaseAffectionRange": {
|
||||
"min": 5,
|
||||
"max": 15
|
||||
},
|
||||
"decreaseAffection": 0.15,
|
||||
"decreaseAffectionRange": {
|
||||
"min": 3,
|
||||
"max": 10
|
||||
}
|
||||
},
|
||||
"randomBad": [
|
||||
{
|
||||
"name": "Raucous Local",
|
||||
"dungeonTitle": "Festival",
|
||||
"fight": {
|
||||
"enemies": [
|
||||
{
|
||||
"name": "bandit heavy",
|
||||
"image": "bandit_heavy",
|
||||
"scaler": 1,
|
||||
"count": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Ride broke down!",
|
||||
"effect": {
|
||||
"healthDamage": 20,
|
||||
"sanityDamage": 25
|
||||
}
|
||||
}
|
||||
],
|
||||
"randomGood": [
|
||||
{
|
||||
"name": "Found a gold pouch!",
|
||||
"effect": {
|
||||
"gold": 100
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "visit a Soul-Thread Weaver",
|
||||
"cost": 250,
|
||||
"aloneCooldown": 20,
|
||||
"alone": {
|
||||
"meetingSomeone": 0.65,
|
||||
"nothingHappens": 0.35,
|
||||
"randomGood": 0.00,
|
||||
"randomBad": 0.00
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
12
src/lineage-json/misc-route/healthOptions.json
Normal file
12
src/lineage-json/misc-route/healthOptions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"serviceName": "Recover Alone",
|
||||
"cost": 0,
|
||||
"heathRestore": 15
|
||||
},
|
||||
{
|
||||
"serviceName": "Visit Master Priest",
|
||||
"cost": 150,
|
||||
"heathRestore": "fill"
|
||||
}
|
||||
]
|
||||
369
src/lineage-json/misc-route/investments.json
Normal file
369
src/lineage-json/misc-route/investments.json
Normal file
@@ -0,0 +1,369 @@
|
||||
[
|
||||
{
|
||||
"name": "Whispering Raven Inn",
|
||||
"description": "It's cheap and in the middle of no-where. Don't expect much foot traffic. But those rare few tired souls will be grateful for a quiet refuge from the beasts of the night.",
|
||||
"requires": {"requirement": "the deed to the whispering raven inn", "message": "A dangerous flood of monsters is spilling out from a nearby cave, preventing anyone from getting close to this rest stop, put an end to the source before further considering purchase.", "removes": false },
|
||||
"cost": 5000,
|
||||
"turnsPerReturn": 1,
|
||||
"goldReturnRange": {"min": 0, "max": 50},
|
||||
"maxGoldStockPile": 3500,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Install Signage",
|
||||
"cost": 1500,
|
||||
"description":"Install signage along nearby roads. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 10, "goldMaximumIncrease": 5}
|
||||
},
|
||||
{
|
||||
"name": "Alcohol License",
|
||||
"cost": 10000,
|
||||
"description":"Alcohol often leads to heavy spenders. Increases maximum gold return.",
|
||||
"effect": {"goldMaximumIncrease": 25}
|
||||
},
|
||||
{
|
||||
"name": "Luxury Rooms",
|
||||
"cost": 17500,
|
||||
"description":"Nicer rooms means you can charge more. Increases minimum gold return.",
|
||||
"effect": {"goldMinimumIncrease": 60}
|
||||
},
|
||||
{
|
||||
"name": "New Wing",
|
||||
"cost": 22500,
|
||||
"description":"More rooms means more bodies at peak. Increases maximum gold return.",
|
||||
"effect": {"goldMaximumIncrease": 135, "maxGoldStockPileIncrease": 1500}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Trading Route",
|
||||
"description": "Control the arteries of commerce, provide a trader with startup costs.",
|
||||
"requires": {"requirement": "head of goblin shaman", "message": "Goblins have been attacking the roads, clear out the goblin cave to ensure that they won't pose a danger.", "removes": true},
|
||||
"cost": 10000,
|
||||
"turnsPerReturn": 10,
|
||||
"goldReturnRange": {"min": 0, "max": 750},
|
||||
"maxGoldStockPile": 2500,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Inexperienced Guard",
|
||||
"cost": 2000,
|
||||
"description":"Hire a nobody to travel with the trader. Increases minimum gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 150}
|
||||
},
|
||||
{
|
||||
"name": "Faster Horses",
|
||||
"cost": 4000,
|
||||
"description":"Purchase horses to shorten travel time. Shortens travel time.",
|
||||
"effect": {"turnsPerRollChange": -2}
|
||||
},
|
||||
{
|
||||
"name": "Sturdy Carriage",
|
||||
"cost": 6500,
|
||||
"description":"Better put together carriage means lower chance of breakdowns and more carry weight. Increases max stockpile size, and shortens travel time.",
|
||||
"effect": {"turnsPerRollChange": -1, "maxGoldStockPileIncrease": 2000}
|
||||
},
|
||||
{
|
||||
"name": "Capital Sales License",
|
||||
"cost": 10000,
|
||||
"description":"Acquire the ability to sell goods within the Capital City's borders. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 50, "goldMaximumIncrease": 400}
|
||||
},
|
||||
{
|
||||
"name": "Experienced Guards",
|
||||
"cost": 17500,
|
||||
"description":"Hire quality guards. Increases minimum gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 500}
|
||||
},
|
||||
{
|
||||
"name": "Expand Caravan",
|
||||
"cost": 25000,
|
||||
"description":"Expanding size of caravan means more of everything, but slows down the route. Increases gold returns, and max stockpile size",
|
||||
"effect": {"turnsPerRollChange": 1, "goldMinimumIncrease": 400, "goldMaximumIncrease": 450, "maxGoldStockPileIncrease": 3500}
|
||||
},
|
||||
{
|
||||
"name": "Regulatory Capture",
|
||||
"cost": 30000,
|
||||
"description":"Bribe a judge to enact regulations few will be able to comply with. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 550, "goldMaximumIncrease": 800}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Village Inn",
|
||||
"description": "A vital haven for weary travelers and thirsty locals alike. On a good night, the air is filled with laughter, music, and the clinking of golden coins (and the potential broken table).",
|
||||
"requires": {"requirement": "broken seal contract", "message": "The writ of sale has been stolen by bandits! Get it back to proceed with the purchase.", "removes": false},
|
||||
"cost": 39500,
|
||||
"turnsPerReturn": 1,
|
||||
"goldReturnRange": {"min": -100, "max": 300},
|
||||
"maxGoldStockPile": 10000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Hire Pretty Tavern Girl",
|
||||
"cost": 4500,
|
||||
"description":"Drunk men are simple creatures. Increases maximum gold returns.",
|
||||
"effect": {"goldMaximumIncrease": 35}
|
||||
},
|
||||
{
|
||||
"name": "Hire Experienced Bartender",
|
||||
"cost": 14000,
|
||||
"description":"Great bartenders keep the drinks flowing. Increases maximum gold return.",
|
||||
"effect": {"goldMaximumIncrease": 75}
|
||||
},
|
||||
{
|
||||
"name": "Hire Intimidating Bouncers",
|
||||
"cost": 22500,
|
||||
"description":"Keeps the rowdy customers under control. Increases minimum gold return.",
|
||||
"effect": {"goldMinimumIncrease": 100}
|
||||
},
|
||||
{
|
||||
"name": "Biergarten",
|
||||
"cost": 37500,
|
||||
"description":"Expand land plot with outdoor area, some may get too rowdy, leading to minor fines. Decreases minimum gold return, increases maximum gold return.",
|
||||
"effect": {"goldMinimumIncrease": -150, "goldMaximumIncrease": 300}
|
||||
},
|
||||
{
|
||||
"name": "'Entertainment' Wing",
|
||||
"cost": 85000,
|
||||
"description":"Use your imagination. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 50, "goldMaximumIncrease": 500}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Spellbook Publisher",
|
||||
"description": "Magic drips from the quill in this establishment, as scribes imbued with arcane knowledge ink the pages of tomes that will guide the next generation of magi.",
|
||||
"requires": {"requirement": "rogue magi fortress", "message": "A nearby fortress filled to craven magi has destroyed this building and sacked the books in its stockpile. You should clear the fortress before beginning the rebuild.", "removes": false},
|
||||
"cost": 75000,
|
||||
"turnsPerReturn": 25,
|
||||
"goldReturnRange": {"min": 500, "max": 5500},
|
||||
"maxGoldStockPile": 25000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Stockpile Room",
|
||||
"cost": 15000,
|
||||
"description":"It's trademarked and highway robbery, but it works. Increases minimum gold return.",
|
||||
"effect": {"maxGoldStockPileIncrease": 15000}
|
||||
},
|
||||
{
|
||||
"name": "Undo-able Ink™",
|
||||
"cost": 22000,
|
||||
"description":"It's trademarked and highway robbery, but it works. Increases minimum gold return.",
|
||||
"effect": {"goldMinimumIncrease": 2500}
|
||||
},
|
||||
{
|
||||
"name": "Exclusivity Contracts",
|
||||
"cost": 50000,
|
||||
"description":"Lock down the best talent. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 1500, "goldMaximumIncrease": 6500}
|
||||
},
|
||||
{
|
||||
"name": "Arcane Quill Stockpile",
|
||||
"cost": 120000,
|
||||
"description":"Quills need not be held, only spoken to, one scribe can use hundreds. Decreases publishing time.",
|
||||
"effect": {"turnsPerRollChange": -12}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Iron Mine",
|
||||
"description": "Deep in the earth, the rhythmic beat of picks against stone echoes out as miners unearth veins of precious iron, indispensable for smiths and warriors.",
|
||||
"requires": {"requirement": "infested mine", "message": "The mine is completely overrun. You will need to clear it before anyone will consider entering it.", "removes":false},
|
||||
"cost": 145000,
|
||||
"turnsPerReturn": 10,
|
||||
"goldReturnRange": {"min": 1200, "max": 3000},
|
||||
"maxGoldStockPile": 35000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Enchanted Steel Tools",
|
||||
"cost": 27500,
|
||||
"description":"Invest in tools to increase workers' efficiency. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 400, "goldMaximumIncrease": 550}
|
||||
},
|
||||
{
|
||||
"name": "Cart System",
|
||||
"cost": 50000,
|
||||
"description":"Install a cart system for more efficient transport of ore. Increases gold returns and max stockpile size.",
|
||||
"effect": {"goldMinimumIncrease": 400, "goldMaximumIncrease": 550, "maxGoldStockPileIncrease": 25000}
|
||||
},
|
||||
{
|
||||
"name": "Miner's Training",
|
||||
"cost": 75000,
|
||||
"description":"Provide advanced training for miners to improve their work. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 1100, "goldMaximumIncrease": 1000}
|
||||
},
|
||||
{
|
||||
"name": "Improved Mining Techniques",
|
||||
"cost": 100000,
|
||||
"description":"Adopt and implement breakthrough mining techniques. Increases gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 900, "goldMaximumIncrease": 1250}
|
||||
},
|
||||
{
|
||||
"name": "Ward Against Cave-Ins",
|
||||
"cost": 150000,
|
||||
"description":"Enchant the mine with magic wards to prevent cave-ins. Increases gold returns and shortens ore extraction time.",
|
||||
"effect": {"turnsPerRollChange": -2, "goldMinimumIncrease": 650, "goldMaximumIncrease": 1100}
|
||||
},
|
||||
{
|
||||
"name": "Profit Sharing",
|
||||
"cost": 200000,
|
||||
"excludes": "Indentured Servitude",
|
||||
"style": "neutral",
|
||||
"description": "Hire a lawyer to draft a plan to share part of the profits with top employees as an incentive. Increases minimum gold returns.",
|
||||
"effect": {"goldMinimumIncrease": 4000, "goldMaximumIncrease": 1000}
|
||||
},
|
||||
{
|
||||
"name": "Indentured Servitude",
|
||||
"cost": 200000,
|
||||
"excludes": "Profit Sharing",
|
||||
"style": "evil",
|
||||
"description":"Bribe nearby city officials for access to their criminal population, its a win-win if you don't consider morality, but that's what the gold is for. Decreases extraction time and dramatically increases gold returns at the cost of max sanity",
|
||||
"effect": {"turnsPerRollChange": -2, "goldMinimumIncrease": 1000, "goldMaximumIncrease": 4250, "changeMaxSanity": -5}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Monster Breeding Ranch",
|
||||
"description": "Here, creatures of nightmare and wonder are reared. Some are bred for their power in battle, others for exotic pets. All fetch a fair price on the market.",
|
||||
"requires": {"requirement":"dark forest", "message": "This project will require an immense amount of land. Clear out the Dark Forest and you will have all the land you need.", "removes":false},
|
||||
"cost": 220000,
|
||||
"turnsPerReturn": 15,
|
||||
"goldReturnRange": {"min": 2000, "max": 6000},
|
||||
"maxGoldStockPile": 15000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Nest Mimicry",
|
||||
"description": "Replicate the natural habitats of different creatures to boost their growth and health. Increases gold returns.",
|
||||
"cost": 65000,
|
||||
"effect": {"goldMinimumIncrease": 500, "goldMaximumIncrease": 1150}
|
||||
},
|
||||
{
|
||||
"name": "Magical Supplements",
|
||||
"description": "Feed beasts nutrient-rich, magic-infused feed to promote growth. Shortens time to market.",
|
||||
"cost": 120000,
|
||||
"effect": {"turnsPerRollChange": -5 }
|
||||
},
|
||||
{
|
||||
"name": "Black Market Sales",
|
||||
"cost": 145000,
|
||||
"excludes": "Ethical Breeding",
|
||||
"style": "evil",
|
||||
"description":"Sell to disreputable buyers. Increases gold returns and decreases time to market. decreases sanity.",
|
||||
"effect": {"turnsPerRollChange": -2, "goldMinimumIncrease": 1500, "goldMaximumIncrease": 4000, "changeMaxSanity": -5}
|
||||
},
|
||||
{
|
||||
"name": "Ethical Breeding",
|
||||
"cost": 145000,
|
||||
"excludes": "Black Market Sales",
|
||||
"style": "neutral",
|
||||
"description":"Only breed and sell creatures ethically, some with pay the premium. Increases maximum gold returns.",
|
||||
"effect": {"goldMaximumIncrease": 5000}
|
||||
},
|
||||
{
|
||||
|
||||
"name": "Extended Territory",
|
||||
"description": "Increase the ranch size, accommodating a larger variety of monsters. Increases gold returns and max stockpile size.",
|
||||
"cost": 210000,
|
||||
"effect": {"goldMinimumIncrease": 1500, "goldMaximumIncrease": 3500, "maxGoldStockPileIncrease": 15000}
|
||||
},
|
||||
{
|
||||
"name": "Enchanted Enclosures",
|
||||
"description": "Enhance the creatures' environments with magic to stimulate faster and more significant growth. Shortens time to market, increases gold returns, and max stockpile size.",
|
||||
"cost": 255000,
|
||||
"effect": {"turnsPerRollChange": -2, "goldMinimumIncrease": 1500,"goldMaximumIncrease": 3000, "maxGoldStockPileIncrease": 10000}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Crystal Mine",
|
||||
"description": "Beneath ominous stone outcroppings, miners burrow deep below all other mines, discovering veins of shimmering crystal. Their glow is mesmerizing, and their magical potential immense.",
|
||||
"requires": {"requirement": "", "message": "", "removes":false},
|
||||
"cost": 480000,
|
||||
"turnsPerReturn": 20,
|
||||
"goldReturnRange": {"min": 7000, "max": 12000},
|
||||
"maxGoldStockPile": 200000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Gem Laden Tools",
|
||||
"cost": 195000,
|
||||
"description":"Invest in enchanted tools to increase workers' success rate in mining. Increases gold returns.",
|
||||
"effect": {"turnsPerRollChange": -3,"goldMinimumIncrease": 3000, "goldMaximumIncrease": 6000}
|
||||
},
|
||||
{
|
||||
"name": "Portal System",
|
||||
"cost": 345000,
|
||||
"description":"Hire magi to create a teleportation system. Significantly decreases time of extraction.",
|
||||
"effect": {"turnsPerRollChange": -5}
|
||||
},
|
||||
{
|
||||
"name": "Explosive Mining",
|
||||
"cost": 460000,
|
||||
"excludes": "Seismic Monitoring",
|
||||
"style": "neutral",
|
||||
"description": "Utilize explosives for rapid extraction. Wildly increases maximum gold returns, decreases minimum gold return.",
|
||||
"effect": {"turnsPerRollChange": -3,"goldMinimumIncrease": -2000, "goldMaximumIncrease": 16000}
|
||||
},
|
||||
{
|
||||
"name": "Seismic Monitoring",
|
||||
"cost": 490000,
|
||||
"excludes": "Profit Sharing",
|
||||
"style": "good",
|
||||
"description":"Hire earth magi to keep watch and temper seismic activity. Increases gold returns and maximum sanity.",
|
||||
"effect": {"goldMinimumIncrease": 7500, "goldMaximumIncrease": 7500, "changeMaxSanity": 5}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Artifact Excavation Site",
|
||||
"description": "Hidden beneath the millennia of earth lie ancient artifacts infused with forgotten magics. Each find promises wealth, power, and a chance to rewrite history.",
|
||||
"requires": {"requirement": "", "message": "", "removes":false},
|
||||
"cost": 1850000,
|
||||
"turnsPerReturn": 50,
|
||||
"goldReturnRange": {"min": 28500, "max": 100000},
|
||||
"maxGoldStockPile": 500000,
|
||||
"upgrades": [
|
||||
{
|
||||
"name": "Magic Detectors",
|
||||
"cost": 575000,
|
||||
"description":"",
|
||||
"effect": {"turnsPerRollChange": -5, "goldMinimumIncrease": 12000, "goldMaximumIncrease": 24000}
|
||||
},
|
||||
{
|
||||
"name": "Renowned Archeologists",
|
||||
"cost": 1350000,
|
||||
"description":"Hire the most preeminent archeolgy experts from around the world to overlook the excavation and to make sure nothing goes overlooked.",
|
||||
"effect": {"turnsPerRollChange": -5, "goldMinimumIncrease": 18000, "goldMaximumIncrease": 40000}
|
||||
},
|
||||
{
|
||||
"name": "Develop Local Infrastructure",
|
||||
"cost": 6500000,
|
||||
"excludes": "Exploit Local Labor",
|
||||
"style": "good",
|
||||
"description": "You will be here a long time, building up local roads, hospitals and fire departments will aid both you and the locals. Reduces gold return, but speeds time to market and increases max sanity.",
|
||||
"effect": {"turnsPerRollChange": -10,"goldMinimumIncrease": -2500, "goldMaximumIncrease": -2500, "changeMaxSanity": 5}
|
||||
},
|
||||
{
|
||||
"name": "Exploit Local Labor",
|
||||
"cost": 5750000,
|
||||
"excludes": "Develop Local Infrastructure",
|
||||
"style": "evil",
|
||||
"description": "Sabotage other local industries leaving the local population with few other options for work. Increases gold returns, and decreases both time to market and player max sanity.",
|
||||
"effect": {"turnsPerRollChange": -5,"goldMinimumIncrease": 10000, "goldMaximumIncrease": 50000, "changeMaxSanity": -5}
|
||||
},
|
||||
{
|
||||
"name": "Rapid Excavation",
|
||||
"cost": 2100000,
|
||||
"excludes": "Careful Excavation",
|
||||
"style": "neutral",
|
||||
"description":"Nothing else matters than moving fast, you may miss things. Decreases time to market, but decreases minimum gold returns.",
|
||||
"effect": {"turnsPerRollChange": -5,"goldMinimumIncrease": -15000}
|
||||
},
|
||||
{
|
||||
"name": "Careful Excavation",
|
||||
"cost": 2100000,
|
||||
"excludes": "Rapid Excavation",
|
||||
"style": "neutral",
|
||||
"description":"Make sure to miss nothing. Decreases time to market but increase returns.",
|
||||
"effect": {"turnsPerRollChange": 5, "goldMinimumIncrease": 45000, "goldMaximumIncrease": 65000}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
89
src/lineage-json/misc-route/jobs.json
Normal file
89
src/lineage-json/misc-route/jobs.json
Normal file
@@ -0,0 +1,89 @@
|
||||
[
|
||||
{
|
||||
"title": "Broomstick Boxer",
|
||||
"cost": {
|
||||
"mana": 5
|
||||
},
|
||||
"qualifications": null,
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 20
|
||||
},
|
||||
"rankMultiplier": 0.15
|
||||
},
|
||||
{
|
||||
"title": "Crusty Cauldron Cleaner",
|
||||
"cost": {
|
||||
"mana": 5,
|
||||
"health": 3
|
||||
},
|
||||
"qualifications": null,
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 30
|
||||
},
|
||||
"rankMultiplier": 0.20
|
||||
},
|
||||
{
|
||||
"title": "Apprentice Scribe",
|
||||
"cost": {
|
||||
"mana": 8
|
||||
},
|
||||
"qualifications": [
|
||||
"high school education"
|
||||
],
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 45
|
||||
},
|
||||
"rankMultiplier": 0.20
|
||||
},
|
||||
{
|
||||
"title": "Imp CareTaker",
|
||||
"cost": {
|
||||
"mana": 7,
|
||||
"health": 4
|
||||
},
|
||||
"qualifications": [
|
||||
"high school education"
|
||||
],
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 55
|
||||
},
|
||||
"rankMultiplier": 0.25
|
||||
},
|
||||
{
|
||||
"title": "Private Dueling Partner",
|
||||
"cost": {
|
||||
"mana": 10,
|
||||
"health": 4
|
||||
},
|
||||
"qualifications": [
|
||||
"high school education",
|
||||
"defense course"
|
||||
],
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 90
|
||||
},
|
||||
"rankMultiplier": 0.25
|
||||
},
|
||||
{
|
||||
"title": "Wild Monster Hunter",
|
||||
"cost": {
|
||||
"mana": 10,
|
||||
"health": 6
|
||||
},
|
||||
"qualifications": [
|
||||
"high school education",
|
||||
"defense course"
|
||||
],
|
||||
"experienceToPromote": 50,
|
||||
"reward": {
|
||||
"gold": 120
|
||||
},
|
||||
"rankMultiplier": 0.30
|
||||
}
|
||||
]
|
||||
|
||||
12
src/lineage-json/misc-route/manaOptions.json
Normal file
12
src/lineage-json/misc-route/manaOptions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"serviceName": "Meditate On The Elements",
|
||||
"cost": 0,
|
||||
"manaRestore": 25
|
||||
},
|
||||
{
|
||||
"serviceName": "Hire Shamanic Guide",
|
||||
"cost": 150,
|
||||
"manaRestore": "fill"
|
||||
}
|
||||
]
|
||||
12
src/lineage-json/misc-route/otherOptions.json
Normal file
12
src/lineage-json/misc-route/otherOptions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"serviceName": "Visit Witch Doctor",
|
||||
"cost": 25,
|
||||
"removeDebuffs": 1
|
||||
},
|
||||
{
|
||||
"serviceName": "Seek Paladin Aid",
|
||||
"cost": 150,
|
||||
"removeDebuffs": 5
|
||||
}
|
||||
]
|
||||
24
src/lineage-json/misc-route/pvpRewards.json
Normal file
24
src/lineage-json/misc-route/pvpRewards.json
Normal file
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "respec potion",
|
||||
"price": 5,
|
||||
"icon": "flask",
|
||||
"description": "gives the user the ability to respec their attributes"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "tome of knowledge",
|
||||
"price": 15,
|
||||
"icon": "book",
|
||||
"description": "provides 1 skill point"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "potion of undeath",
|
||||
"price": 20,
|
||||
"icon": "potion",
|
||||
"description": "reduces the users age by 1 year"
|
||||
}
|
||||
]
|
||||
|
||||
12
src/lineage-json/misc-route/sanityOptions.json
Normal file
12
src/lineage-json/misc-route/sanityOptions.json
Normal file
@@ -0,0 +1,12 @@
|
||||
[
|
||||
{
|
||||
"serviceName": "Pray",
|
||||
"cost": 0,
|
||||
"sanityRestore": 10
|
||||
},
|
||||
{
|
||||
"serviceName": "Seek Spiritual Leader",
|
||||
"cost": 200,
|
||||
"sanityRestore": "fill"
|
||||
}
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user