Browse Source

Merge branch 'v1.0'

master
许孟阳 2 months ago
parent
commit
76763bb60c
  1. 5
      java/application.properties
  2. 46
      java/src/main/java/vip/xumy/idle/server/conf/Configer.java
  3. 49
      java/src/main/java/vip/xumy/idle/server/ctrl/ArchiveController.java
  4. 26
      java/src/main/java/vip/xumy/idle/server/ctrl/PublicController.java
  5. 33
      java/src/main/java/vip/xumy/idle/server/mapper/IArchiveMapper.java
  6. 4
      java/src/main/java/vip/xumy/idle/server/mapper/IUserMapper.java
  7. 27
      java/src/main/java/vip/xumy/idle/server/pojo/Archive.java
  8. 18
      java/src/main/java/vip/xumy/idle/server/pojo/User.java
  9. 39
      java/src/main/java/vip/xumy/idle/server/service/ArchiveService.java
  10. 51
      java/src/main/java/vip/xumy/idle/server/service/UserService.java
  11. 205
      java/src/main/java/vip/xumy/idle/server/util/LoginUtil.java
  12. 1
      java/src/main/resources/application.properties
  13. BIN
      public/img/menu/settings.png
  14. 61
      src/api/base.ts
  15. 21
      src/api/index.ts
  16. 20
      src/components/dialog.vue
  17. 2
      src/components/equip.vue
  18. 1
      src/config/assets.ts
  19. 8
      src/config/base.ts
  20. 15
      src/config/beings.ts
  21. 2
      src/config/i18n/zh/euips.ts
  22. 10
      src/config/i18n/zh/index.ts
  23. 4
      src/config/i18n/zh/setting.ts
  24. 4
      src/config/i18n/zh/skills.ts
  25. 8
      src/config/skill/armor.ts
  26. 8
      src/config/skill/base.ts
  27. 6
      src/config/skill/bracers.ts
  28. 11
      src/config/skill/buff.ts
  29. 4
      src/config/skill/jewelry.ts
  30. 16
      src/config/skill/neck.ts
  31. 4
      src/config/skill/pants.ts
  32. 14
      src/config/skill/ring.ts
  33. 14
      src/config/skill/weapon.ts
  34. 3
      src/store/mutation.ts
  35. 2
      src/store/state.ts
  36. 7
      src/tool/IndexedDB.ts
  37. 3
      src/tool/caller/attribute.ts
  38. 21
      src/tool/caller/battle.ts
  39. 4
      src/tool/crypot.ts
  40. 2
      src/tool/random.ts
  41. 69
      src/views/archive.vue
  42. 4
      src/views/backpack/auto-sell.vue
  43. 2
      src/views/backpack/backpack.vue
  44. 7
      src/views/backpack/equip-menu.vue
  45. 27
      src/views/backpack/grid.vue
  46. 8
      src/views/backpack/inherited.vue
  47. 16
      src/views/backpack/player.vue
  48. 2
      src/views/backpack/strengthen.vue
  49. 8
      src/views/dungeon/battle.vue
  50. 18
      src/views/dungeon/dungeonTips.vue
  51. 2
      src/views/illustrated/illustrated.vue
  52. 4
      src/views/index.vue
  53. 64
      src/views/login.vue
  54. 5
      src/views/menu.vue
  55. 67
      src/views/message/sys-info.vue
  56. 60
      src/views/point/point.vue
  57. 135
      src/views/setting.vue
  58. 2
      src/views/shop/shop.vue
  59. 35
      src/views/version/update-log.vue
  60. 2
      src/views/version/version.vue
  61. 14
      vue.config.js

5
java/application.properties

@ -1,4 +1,7 @@ @@ -1,4 +1,7 @@
# 程序自身数据源配置
spring.datasource.url=jdbc:mysql://10.100.0.108:3306/idle_game?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true
spring.datasource.username=root
spring.datasource.password=mBMjp2v74c7MzhC/5RGeXF1V3E+AcRFs1f5OH6PDHi3nWaM3njaaoewswq8Sl7/AY631t0sONVDG672pX4mFpZx/8xex8BJP3uX1wUu9NGpTCSHskb5cD6KZMNV4jNsfoqxFRyJq8yk86djPsCfR4ch0sPnLH+LCg9XY1DAw8szh93QnKDkiImq2JLkaIwG3R3t8dNWv1wVoMR6vVecPsEUyPJu5vsrvJhjP3uAL7jZYJVGZG6bkrpV3R6I6mja0QnTdF41NCL5Ex0TINSi7GKnrALjZ0qWcT9fe2bTUCKq50+CtVEAQnEz2ZJpYUaBZXJbHh4OrUyqjAmA5s7IelQ==
spring.datasource.password=123456
login.token.timeout=10080
login.token.domain=

46
java/src/main/java/vip/xumy/idle/server/conf/Configer.java

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
package vip.xumy.idle.server.conf;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
/** Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Configuration
public class Configer {
@Bean
public HttpMessageConverter<?> configureMessageConverters() {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
SerializerFeature.WriteMapNullValue,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero,
SerializerFeature.WriteNullListAsEmpty,
SerializerFeature.WriteNullBooleanAsFalse,
SerializerFeature.DisableCircularReferenceDetect
);
converter.setFastJsonConfig(config);
converter.setDefaultCharset(Charset.forName("UTF-8"));
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_JSON);
converter.setSupportedMediaTypes(mediaTypeList);
return converter;
}
}

49
java/src/main/java/vip/xumy/idle/server/ctrl/ArchiveController.java

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
package vip.xumy.idle.server.ctrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.xumy.core.pojo.com.BaseResponse;
import vip.xumy.idle.server.pojo.Archive;
import vip.xumy.idle.server.service.ArchiveService;
import vip.xumy.idle.server.util.LoginUtil;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@RestController
@RequestMapping("archive")
public class ArchiveController {
@Autowired
private ArchiveService archiveService;
@PostMapping
public BaseResponse saveArchive(@RequestBody Archive archive) {
String userId = LoginUtil.getUserId();
if (userId == null) {
return new BaseResponse(true, "请先登录");
}
archive.setUsername(userId);
archiveService.saveOrUpdate(archive);
return new BaseResponse(true, "存档保存成功");
}
@GetMapping
public BaseResponse getArchive(String version) {
String userId = LoginUtil.getUserId();
Archive archive = archiveService.getByKey(userId, version);
if (archive == null) {
return new BaseResponse(false, "未查询到你的存档");
}
return new BaseResponse(archive.getArchive());
}
}

26
java/src/main/java/vip/xumy/idle/server/ctrl/PublicController.java

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
package vip.xumy.idle.server.ctrl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -7,8 +8,12 @@ import org.springframework.web.bind.annotation.RequestMapping; @@ -7,8 +8,12 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import vip.xumy.core.pojo.com.BaseResponse;
import vip.xumy.core.utils.StringUtil;
import vip.xumy.idle.server.pojo.SocketMsg;
import vip.xumy.idle.server.pojo.User;
import vip.xumy.idle.server.service.UserService;
import vip.xumy.idle.server.service.WebSocketService;
import vip.xumy.idle.server.util.LoginUtil;
/**
* Ownership belongs to the company
@ -20,6 +25,8 @@ import vip.xumy.idle.server.service.WebSocketService; @@ -20,6 +25,8 @@ import vip.xumy.idle.server.service.WebSocketService;
@RestController
@RequestMapping("public")
public class PublicController {
@Autowired
private UserService userService;
@GetMapping("socket/num")
public BaseResponse getSocketNum() {
@ -32,4 +39,23 @@ public class PublicController { @@ -32,4 +39,23 @@ public class PublicController {
return new BaseResponse();
}
@PostMapping("login")
public BaseResponse login(@RequestBody User param) {
User user = userService.login(param);
if (user == null) {
return new BaseResponse(false, "登录失败,用户名或密码错误");
}
LoginUtil.saveLoginInfo(user);
return new BaseResponse(user);
}
@GetMapping("login")
public BaseResponse getLogin() {
User user = LoginUtil.getUserInfo();
if (StringUtil.isEmpty(user.getUsername())) {
return new BaseResponse(null);
}
return new BaseResponse(user);
}
}

33
java/src/main/java/vip/xumy/idle/server/mapper/IArchiveMapper.java

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
package vip.xumy.idle.server.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import vip.xumy.idle.server.pojo.Archive;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Mapper
public interface IArchiveMapper extends BaseMapper<Archive> {
@Update("""
UPDATE archive
SET
lv = #{lv},
coins = #{coins},
strengthen_lv= #{strengthenLv} ,
archive = #{archive}
WHERE
username = #{username}
and version = #{version}
""")
void update(Archive archive);
}

4
java/src/main/java/vip/xumy/idle/server/mapper/IUserMapper.java

@ -16,8 +16,8 @@ import vip.xumy.idle.server.pojo.User; @@ -16,8 +16,8 @@ import vip.xumy.idle.server.pojo.User;
public interface IUserMapper extends BaseMapper<User> {
@Select("""
SELECT username, state FROM user WHERE username = #{username} AND password = #{password}
UPDATE user SET last_login = NOW() WHERE username = #{username};
""")
User login(User param);
User login(String username);
}

27
java/src/main/java/vip/xumy/idle/server/pojo/Archive.java

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
package vip.xumy.idle.server.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Setter
@Getter
@TableName("archive")
public class Archive {
private String username;
private String version;
private int lv;
private long coins;
private int strengthenLv;
private String archive;
}

18
java/src/main/java/vip/xumy/idle/server/pojo/User.java

@ -1,29 +1,33 @@ @@ -1,29 +1,33 @@
package vip.xumy.idle.server.pojo;
import com.alibaba.fastjson.annotation.JSONField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
/** Ownership belongs to the company
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年4月18日
* @author:mengyxu
* @date:2025年4月18日
*/
@Setter
@Getter
@TableName("user")
public class User {
private String useranme;
@TableId
private String username;
@JSONField(serialize = false)
private String password;
private String state;
private String phone;
private String idCard;
private String name;
private String registerTime;
private String last_login;
private String lastLogin;
}

39
java/src/main/java/vip/xumy/idle/server/service/ArchiveService.java

@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
package vip.xumy.idle.server.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import vip.xumy.idle.server.mapper.IArchiveMapper;
import vip.xumy.idle.server.pojo.Archive;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Service
public class ArchiveService {
@Autowired
private IArchiveMapper archiveMapper;
public void saveOrUpdate(Archive archive) {
Archive exit = getByKey(archive.getUsername(), archive.getVersion());
if (exit == null) {
archiveMapper.insert(archive);
} else {
archiveMapper.update(archive);
}
}
public Archive getByKey(String username, String version) {
QueryWrapper<Archive> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
wrapper.eq("version", version);
return archiveMapper.selectOne(wrapper);
}
}

51
java/src/main/java/vip/xumy/idle/server/service/UserService.java

@ -0,0 +1,51 @@ @@ -0,0 +1,51 @@
package vip.xumy.idle.server.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import vip.xumy.core.utils.DateUtil;
import vip.xumy.core.utils.StringUtil;
import vip.xumy.idle.server.mapper.IUserMapper;
import vip.xumy.idle.server.pojo.User;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2025年5月19日
*/
@Service
public class UserService {
@Autowired
private IUserMapper userMapper;
public User login(User param) {
String username = param.getUsername();
String password = param.getPassword();
if (StringUtil.isEmpty(username, password)) {
return null;
}
User user = getById(username);
if (user != null) {
if (password.equals(user.getPassword())) {
userMapper.login(username);
return user;
} else {
return null;
}
} else {
String time = DateUtil.format();
param.setState("0");
param.setRegisterTime(time);
param.setLastLogin(time);
userMapper.insert(param);
return param;
}
}
public User getById(String username) {
return userMapper.selectById(username);
}
}

205
java/src/main/java/vip/xumy/idle/server/util/LoginUtil.java

@ -0,0 +1,205 @@ @@ -0,0 +1,205 @@
package vip.xumy.idle.server.util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import vip.xumy.core.golbal.GlobalBuffer;
import vip.xumy.core.pojo.com.Cache;
import vip.xumy.core.utils.StringUtil;
import vip.xumy.idle.server.pojo.User;
/**
* Ownership belongs to the company
*
* @author:mengyxu
* @date:2024年3月5日
*/
//@Log4j2
@Component
public class LoginUtil {
public static final String TIKEN_KEY_PREFIX = "token-";
public static final String LOGIN_COOKIE_NAME = "token";
@Value("${login.token.timeout}")
public void setTimeout(Integer timeout) {
LoginUtil.timeout = timeout;
}
private static Integer timeout;
@Value("${login.token.domain}")
public void setDomain(String domain) {
LoginUtil.domain = domain;
}
private static String domain;
private static HttpServletRequest request;
@Autowired
public void setRequest(HttpServletRequest request) {
LoginUtil.request = request;
}
private static HttpServletResponse response;
@Autowired
public void setResponse(HttpServletResponse response) {
LoginUtil.response = response;
}
private static String getTokenKey(String userId) {
return TIKEN_KEY_PREFIX + userId;
}
public static boolean isLogin(String userId) {
Cache cache = GlobalBuffer.getCache(getTokenKey(userId));
return !Cache.isEmpty(cache);
}
public static void remveLoginInfo(String userId) {
String tokenKey = LoginUtil.getTokenKey(userId);
Cache token = GlobalBuffer.getCache(tokenKey);
if (!Cache.isEmpty(token)) {
String value = token.getValue();
GlobalBuffer.removeCache(value.substring(0, 10));
GlobalBuffer.removeCache(tokenKey);
}
}
public static void saveLoginInfo(User user) {
// 删除旧的token信息
String userId = user.getUsername();
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId));
if (!Cache.isEmpty(exitToken)) {
String value = exitToken.getValue();
GlobalBuffer.removeCache(value.substring(0, 10));
}
// 计算新的token
String ip = getIpAddr();
String seq = GlobalBuffer.getSeq();
String token = seq + StringUtil.md5(user.getUsername() + ip + System.currentTimeMillis(), false);
// 保存用户token
GlobalBuffer.addCache(LoginUtil.getTokenKey(userId), new Cache(token, timeout * 60));
// 保存token的用户信息
GlobalBuffer.addCache(seq, new Cache(user, timeout * 60));
LoginUtil.addToken(token, response);
}
private static void addToken(String token, HttpServletResponse response) {
Cookie cookie = new Cookie(LOGIN_COOKIE_NAME, token);
if (!StringUtil.isEmpty(domain)) {
cookie.setDomain(domain);
}
cookie.setPath("/");
response.addCookie(cookie);
}
public static User getUserInfo(String token, boolean refresh) {
if (StringUtil.isEmpty(token)) {
token = getToken();
}
User empty = new User();
if (StringUtil.isEmpty(token) || token.length() != 42) {
return empty;
}
Cache userCache = GlobalBuffer.getCache(token.substring(0, 10));
if (Cache.isEmpty(userCache)) {
return empty;
}
User user = userCache.getValue();
String userId = user.getUsername();
Cache exitToken = GlobalBuffer.getCache(LoginUtil.getTokenKey(userId));
if (Cache.isEmpty(exitToken)) {
return empty;
}
if (StringUtil.equals(token, exitToken.getValue())) {
if (refresh) {
userCache.refresh();
exitToken.refresh();
}
return user;
}
return empty;
}
public static String getUserId() {
return getUserInfo(null, false).getUsername();
}
public static String getUserIdAndRefresh() {
return getUserInfo(null, true).getUsername();
}
public static User getUserInfo() {
return getUserInfo(null, false);
}
public static void loginOut() {
String token = LoginUtil.getToken();
if (!StringUtil.isEmpty(token)) {
String seq = token.substring(0, 10);
Cache userCache = GlobalBuffer.getCache(seq);
if (!Cache.isEmpty(userCache)) {
User user = userCache.getValue();
String userId = user.getUsername();
GlobalBuffer.removeCache(getTokenKey(userId));
}
GlobalBuffer.removeCache(seq);
}
}
public static String getToken() {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return null;
}
for (Cookie cookie : cookies) {
if (LOGIN_COOKIE_NAME.equals(cookie.getName())) {
return cookie.getValue();
}
}
return null;
}
/**
* 获取访问者IP
*
* 在一般情况下使用Request.getRemoteAddr()即可但是经过nginx等反向代理软件后这个方法会失效
*
* 本方法先从Header中获取X-Real-IP如果不存在再从X-Forwarded-For获得第一个IP(,分割) 如果还不存在则调用Request
* .getRemoteAddr()
*
* @param request
* @return
*/
public static String getIpAddr() {
String ip = request.getHeader("X-Real-IP");
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
return ip;
}
ip = request.getHeader("X-Forwarded-For");
if (!StringUtil.isEmpty(ip) && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个IP值,第一个为真实IP。
int index = ip.indexOf(',');
if (index != -1) {
return ip.substring(0, index);
} else {
return ip;
}
} else {
return request.getRemoteAddr();
}
}
}

1
java/src/main/resources/application.properties

@ -35,4 +35,3 @@ pagehelper.params=count=countSql @@ -35,4 +35,3 @@ pagehelper.params=count=countSql
pagehelper.returnPageInfo=check
version.num=1.0.1
version.date=2025-03-07
disk.info.path=

BIN
public/img/menu/settings.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

61
src/api/base.ts

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
let commit;
export const setCommit = (data) => {
commit = data;
};
export const post = (url, data) => {
const t = new Date().getTime();
data.t = t;
const options: any = {
method: 'POST',
credentials: 'same-origin', // 设置为 同源 以发送 Cookie
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
};
return new Promise((reslove, reject) => {
fetch(url, options)
.then(responseToJson)
.then((data) => reslove(getResult(data)))
.catch((error) => reslove(false));
});
};
export const get = (url, data?) => {
const t = new Date().getTime();
if (data) {
data.t = t;
const params = new URLSearchParams(data);
url += '?' + params;
} else {
url += '?t=' + t;
}
const options: any = {
method: 'GET',
credentials: 'same-origin', // 设置为 同源 以发送 Cookie
headers: {
'Content-Type': 'application/json',
},
};
return new Promise((reslove, reject) => {
fetch(url.toString(), options)
.then(responseToJson)
.then((data) => reslove(getResult(data)))
.catch((error) => reslove(false));
});
};
const responseToJson = (response) => {
if (response.ok) {
return response.json();
} else {
commit('set_sys_info', { msg: '网络错误', type: 'warning' });
}
};
const getResult = (data) => {
if (data.message) {
commit('set_sys_info', { msg: data.message, type: data.success ? 'win' : 'warning' });
}
return data.data;
};

21
src/api/index.ts

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
import { post, get, setCommit } from './base';
export { setCommit };
export const api_root = '/api';
const urls = {
login: api_root + '/public/login',
archive: api_root + '/archive',
};
export const loginOrRegister = (param) => {
return post(urls.login, param);
};
export const getUser = () => {
return get(urls.login);
};
export const uploadArchive = (archive) => {
return post(urls.archive, archive);
};
export const downArchive = (param) => {
return get(urls.archive, param);
};

20
src/components/dialog.vue

@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
<span>{{ title }}</span>
</div>
<slot />
<img v-if="showHeader" :src="close_icon" class="close" @click="show = false; emit('close')"></img>
<img v-if="showHeader" :src="close_icon" class="close" @click="show = false; emit('close');"></img>
</div>
</div>
</teleport>
@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { watch, onMounted, ref } from "vue";
import { watch, onMounted, ref, onBeforeUnmount } from "vue";
import { useI18n } from "vue3-i18n";
import { close_icon } from "@/config";
@ -77,12 +77,15 @@ watch(() => prop.modelValue, (n, o) => { @@ -77,12 +77,15 @@ watch(() => prop.modelValue, (n, o) => {
show.value = n;
})
const keydown = (e) => {
if (e.keyCode == 27) {
show.value = false;
emit('close');
}
}
onMounted(() => {
document.addEventListener('keydown', (e) => {
if (e.keyCode == 27) {
show.value = false;
}
})
document.addEventListener('keydown', keydown);
if (prop.obscured) {
style.value = {
height: '100%'
@ -91,6 +94,9 @@ onMounted(() => { @@ -91,6 +94,9 @@ onMounted(() => {
style.value = {};
}
});
onBeforeUnmount(() => {
document.removeEventListener('keydown', keydown)
})
</script>
<style lang="scss" scoped>
.dialog {

2
src/components/equip.vue

@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
<div class="entry">
<div v-for="v in equip.base.entry" :key="v.id">
<span>
{{ t(v.type + '.0') }} : {{ v.showVal }}
{{ t(v.type + '.0') }} : {{ v.showVal }}({{ v.percent }}%)
</span>
<span v-if="equip.sample">
[{{ v.min }} - {{ v.max }}]

1
src/config/assets.ts

@ -20,6 +20,7 @@ export const menu_icons = { @@ -20,6 +20,7 @@ export const menu_icons = {
illustrated: root + '/img/menu/illustrated.png',
extras: root + '/img/menu/extras.png',
setting: root + '/img/menu/setting.png',
settings: root + '/img/menu/settings.png',
};
export const attr_icon_urls = {

8
src/config/base.ts

@ -14,3 +14,11 @@ export const point_coefficients = { @@ -14,3 +14,11 @@ export const point_coefficients = {
};
export const player_move_time = 3000;
export const player_battle_time = 1000;
export const battle_msg_types = {
attack: 'attack',
crit: 'crit',
gain: 'gain',
debuff: 'debuff',
extra: 'extra',
};

15
src/config/beings.ts

@ -52,6 +52,12 @@ export class Attribute { @@ -52,6 +52,12 @@ export class Attribute {
});
}
}
copy(attr: Attribute) {
Object.keys(attr).forEach((key) => {
this[key] = attr[key];
});
}
}
export class Player {
@ -96,7 +102,11 @@ export class Monster extends Attribute { @@ -96,7 +102,11 @@ export class Monster extends Attribute {
this.difficulty = difficulty;
this.df = base_attr_factor[this.difficulty];
this.ef = extra_factor[difficulty];
this.lf = ((this.lv + layer - 1) / this.lv) ** 2;
if (layer == 0) {
this.lf = 1;
} else {
this.lf = ((this.lv + layer - 1) / this.lv) ** 2;
}
this.callAtk(2.5);
this.callHp(17);
this.callCoins(11);
@ -137,7 +147,8 @@ export class BossMonster extends Monster { @@ -137,7 +147,8 @@ export class BossMonster extends Monster {
const rf = rate_factor[difficulty];
this.equipRates = [0.25 - 0.05 * rf, 0.55 - 0.1 * rf, 0.15 + 0.1 * rf, 0.05 + 0.05 * rf];
let uniqueRate = 0.02 * ((rf - 1) * 5 + 1);
const colorfulRate = 0.02 * (rf - 3) * this.lf;
let colorfulRate = 0.02 * (rf - 3) * this.lf;
colorfulRate = colorfulRate > 1 ? 1 : colorfulRate;
if (uniqueRate + colorfulRate > 1) {
uniqueRate = 1 - colorfulRate;
}

2
src/config/i18n/zh/euips.ts

@ -221,7 +221,7 @@ export const bracers = { @@ -221,7 +221,7 @@ export const bracers = {
huojing: ['火晶环', '闻上去有股老君八卦炉中丹屑的味道。'],
xingjia: ['刑枷', '我无法为野心套上邢枷,所以只好走向毁灭。'],
meipusa: ['美菩萨', '是因为美丽?还是因为菩萨?'],
rsggu: ['人参果裹', '不吃也要拿个碗盖好嘛,你看现在爬得满桌都是血...... ----清风'],
rsggu: ['人参果裹', '不吃也要拿个碗盖好嘛,你看现在爬得满桌都是血...... ----清风'],
duoqing: ['多情腕', '多情自古空余恨,此恨绵绵无绝期。'],
sibuxiang: ['四不像', '不要理会别人说你像谁或者不像,做你自己。'],
wano: ['玩偶', '削去强大的骨肉,用脆弱的藕节连上傀儡的丝线。'],

10
src/config/i18n/zh/index.ts

@ -1,6 +1,7 @@ @@ -1,6 +1,7 @@
import { weapon, armor, neck, ring, jewelry, pants, shoes, bracers, quality, extraQuality } from './euips';
import * as skills from './skills';
import * as point from './point';
import * as setting from './setting';
export default class Zh {
title = '挂机放置游戏';
@ -153,9 +154,11 @@ export default class Zh { @@ -153,9 +154,11 @@ export default class Zh {
saveGame = ['保存游戏(Ctrl+S)', '每5分钟会自动保存游戏一次', '游戏进度已经保存了。'];
archive = ['存档管理(A)', '导入存档前请将存档内容粘贴到输入框内'];
copyArchive = ['复制存档', '已经复制存档了,建议保存到备忘录', '复制存档失败'];
copyArchive = ['复制存档', '已经复制存档了,建议保存到备忘录', '复制存档失败', '复制旧存档'];
pasteArchive = ['粘贴存档', '粘贴存档内容到输入框成功', '粘贴失败'];
cleanArchive = ['删除存档'];
uploadArchive = '上传存档';
downArchive = '下载存档';
importArchive = ['导入', '导入存档成功,继续游戏吧!', '导入存档失败', '存档版本已过期,无法导入!'];
experiential = ['导入体验存档成功,体验时间${0}分钟。', '体验存档无法保存!', '体验时间已过,自动读取本地存档。'];
@ -165,4 +168,9 @@ export default class Zh { @@ -165,4 +168,9 @@ export default class Zh {
version = ['版本信息和更新日志(U)'];
update = ['版本更新通知', '检测到有服务器有新版本,是否刷新刷新页面更新版本?', '刷新页面', '暂时不管'];
login = ['登录', '用户名', '密码', '登录/注册', '请输入用户名', '请输入密码', '登录成功'];
setting = setting;
}

4
src/config/i18n/zh/setting.ts

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
export const title = '系统设置(ESC)';
export const action = ['保存设置', '取消'];
export const music = ['背景音乐', '完全关闭', '最小音量', '正常音量'];
export const battle = ['战斗日志', '显示', '隐藏'];

4
src/config/i18n/zh/skills.ts

@ -9,7 +9,7 @@ export const attack = ['普通攻击', '伤害倍率100%', '${0}使用了${1}${4 @@ -9,7 +9,7 @@ export const attack = ['普通攻击', '伤害倍率100%', '${0}使用了${1}${4
export const iceBlade = ['冰刃', '暴击时有${0}几率释放冰线冲击,附加${1}%攻击力的伤害和${2}回合冰冻效果。', '触发了冰刃,附加${0}点伤害,冰冻${1}${2}回合'];
export const seeRed = ['见红', '对目标施加${0}层流血,持续${1}回合。', '冷却${0}回合。'];
export const qici = ['鳍刺', '攻击时有${0}%概率对目标施加${1}层流血,持续${2}回合。', '触发鳍刺,对${0}施加${1}层流血,持续${2}回合。'];
export const baonue = ['暴虐', '攻击时有${0}%概率使目标筋脉爆裂,施加满层流血,持续${1}回合。', '触发暴虐,对${0}施加满层流血,持续${2}回合。'];
export const baonue = ['暴虐', '攻击时有${0}%概率使目标筋脉爆裂,施加满层流血,持续${1}回合。', '触发暴虐,对${0}施加满层流血,持续${1}回合。'];
export const zhaxin = ['扎心', '获得${0}%暴击伤害加成。'];
export const aozhidu = ['鳌之毒', '攻击时使目标进入溃烂状态${0}回合。', '触发鳌之毒,${0}进入溃烂状态${1}回合'];
export const shijiucha = ['十九叉', '每九次攻击获得连刺状态,使得第十次攻击附加${0}倍伤害。', '${0}触发十九叉连刺,附加${0}点伤害'];
@ -64,7 +64,7 @@ export const liulipan = ['琉璃盘', '使用后产生黑红内丹,临时提高$ @@ -64,7 +64,7 @@ export const liulipan = ['琉璃盘', '使用后产生黑红内丹,临时提高$
export const JHSY = ['镜花水月', '被攻击时有${0}%概率反弹${1}%所受伤害。', '${0}触发了镜花水月,反弹${1}点伤害。'];
export const lizhao = ['利爪', '攻击时有${0}%概率增加${1}%技能伤害倍率。', '触发利爪,增加${0}%技能伤害倍率。'];
export const judu = ['剧毒', '被攻击时有${0}%概率喷出毒液,使目标进入溃烂状态${1}回合。', '触发剧毒,${0}进溃烂状态${1}回合。'];
export const judu = ['剧毒', '被攻击时有${0}%概率喷出毒液,使目标进入溃烂状态${1}回合。', '触发剧毒,${0}进溃烂状态${1}回合。'];
export const xianglong = ['降龙', '攻击时,若生命值低于${0}%,增加${1}%伤害加成。', '触发降龙,增加${1}%伤害加成。'];
export const dalidan = ['大力丹', '提升${0}%攻击加成。'];

8
src/config/skill/armor.ts

@ -19,7 +19,7 @@ export class BHXDJC extends PrePassiveSkill { @@ -19,7 +19,7 @@ export class BHXDJC extends PrePassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const shield = Math.ceil((owner.attr.hp * this.shieldPercentOfHp) / 100);
owner.shield += shield;
owner.battleLog(replace(t('skill.bhxdjc.2'), [shield]));
owner.gainLog(replace(t('skill.bhxdjc.2'), [shield]));
}
}
//铁壁
@ -35,7 +35,7 @@ export class TieBi extends BuffSkill { @@ -35,7 +35,7 @@ export class TieBi extends BuffSkill {
owner.extraAttr.dmgReduc = callDmgReduc(owner.extraAttr.dmgReduc, this.dmgReduc);
}
log(owner: BattleRole, target: BattleRole): void {
owner.battleLog(replace(t('skill.tiebi.2'), [t(owner.type), this.dmgReduc, this.last]));
owner.gainLog(replace(t('skill.tiebi.2'), [t(owner.type), this.dmgReduc, this.last]));
}
}
//督军的潜能
@ -51,7 +51,7 @@ export class DuJunQianNeng extends PrePassiveSkill { @@ -51,7 +51,7 @@ export class DuJunQianNeng extends PrePassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
owner.extraAttr.dmgReduc = callDmgReduc(owner.extraAttr.dmgReduc, this.dmgReduc);
owner.battleLog(replace(t('skill.dujunqianneng.2'), [this.hpPercent, this.dmgReduc]));
owner.gainLog(replace(t('skill.dujunqianneng.2'), [this.hpPercent, this.dmgReduc]));
}
}
//金光护身
@ -67,7 +67,7 @@ export class JinGuangHuShen extends CounterSkill { @@ -67,7 +67,7 @@ export class JinGuangHuShen extends CounterSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
owner.addHp((owner.attr.hp * this.hpPercent) / 100);
owner.battleLog(replace(t('skill.jinguanghushen.2'), [this.hpPercent]));
owner.gainLog(replace(t('skill.jinguanghushen.2'), [this.hpPercent]));
}
}
//牢不可破

8
src/config/skill/base.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import { BattleRole, callReducPercent, replace } from '@/tool';
import { type_boss } from '@/config';
import { battle_msg_types, type_boss } from '@/config';
import i18n from '../i18n';
import { ControlBuff } from './buff';
const { t } = i18n;
@ -139,7 +139,7 @@ export abstract class Vampire extends SufPassiveSkill { @@ -139,7 +139,7 @@ export abstract class Vampire extends SufPassiveSkill {
owner.addHp(sneak);
if (sneak > 0) {
const log = replace(t('skill.vampire.2'), [sneak]);
owner.battleLog(log);
owner.gainLog(log);
}
}
}
@ -156,7 +156,7 @@ export abstract class Control extends ActionSkill { @@ -156,7 +156,7 @@ export abstract class Control extends ActionSkill {
log = replace(t('skill.control.0'), [t(target.type), this.last]);
}
log = log = replace(t('skill.user'), [t(owner.type), t('skill.' + this.name + '.0')]) + log;
owner.battleLog(log);
owner.atteckLog(log);
}
}
//主动攻击技能(普通攻击)
@ -175,7 +175,7 @@ export class Attack extends ActionSkill { @@ -175,7 +175,7 @@ export class Attack extends ActionSkill {
if (owner.dmg) {
target.addHp(-1 * owner.dmg);
const log = replace(t('skill.attack.2'), [t(owner.type), t('skill.' + this.name + '.0'), t(target.type), owner.dmg, critLog]);
owner.battleLog(log);
owner.atteckLog(log);
}
}
}

6
src/config/skill/bracers.ts

@ -18,7 +18,7 @@ export class Xianglong extends PrePassiveSkill { @@ -18,7 +18,7 @@ export class Xianglong extends PrePassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const extra = owner.extraAttr;
extra.dmgPercent = callDmgPercent(extra.dmgPercent, this.dmgPercent);
owner.battleLog(replace(t('skill.xianglong.2'), [this.hpPercent, this.dmgPercent]));
owner.gainLog(replace(t('skill.xianglong.2'), [this.hpPercent, this.dmgPercent]));
}
}
//大力丹
@ -47,7 +47,7 @@ export class JuDu extends CounterSkill { @@ -47,7 +47,7 @@ export class JuDu extends CounterSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const judu = new KuiLan('kuilan', this.last);
target.putBuff(judu);
owner.battleLog(replace(t('skill.judu.2'), [t(target.type), this.last]));
owner.gainLog(replace(t('skill.judu.2'), [t(target.type), this.last]));
}
}
//利爪
@ -63,6 +63,6 @@ export class LiZhao extends PrePassiveSkill { @@ -63,6 +63,6 @@ export class LiZhao extends PrePassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
owner.skillPercent += this.percent;
owner.battleLog(replace(t('skill.lizhao.2'), [this.percent]));
owner.gainLog(replace(t('skill.lizhao.2'), [this.percent]));
}
}

11
src/config/skill/buff.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { BattleRole, callDmgPercent, callDmgReduc, replace } from '@/tool';
import { BattleRole, callDmgPercent, callDmgReduc, callReducPercent, replace } from '@/tool';
import i18n from '../i18n';
const { t } = i18n;
@ -138,7 +138,7 @@ export class BlocPercentBuff extends PercentAttackedBuff { @@ -138,7 +138,7 @@ export class BlocPercentBuff extends PercentAttackedBuff {
return replace(t('skill.blocbuff.2'), [this.percent * this.layer]);
}
takeEffect(owner: BattleRole): void {
owner.extraAttr.bloc += Math.ceil(owner.attr.bloc * this.percent);
owner.extraAttr.bloc += Math.ceil((owner.attr.bloc * this.percent) / 100);
}
}
//控制异常
@ -151,7 +151,7 @@ export class ControlBuff extends AttackBuff { @@ -151,7 +151,7 @@ export class ControlBuff extends AttackBuff {
}
takeEffect(owner: BattleRole): void {
owner.action = null;
owner.battleLog(replace(t('skill.control.2'), [t('skill.' + this.name + '.0'), t(owner.type)]));
owner.debuffLog(replace(t('skill.control.2'), [t('skill.' + this.name + '.0'), t(owner.type)]));
}
}
//溃烂
@ -196,8 +196,9 @@ export class LiuXue extends AttackBuff { @@ -196,8 +196,9 @@ export class LiuXue extends AttackBuff {
return replace(t('skill.liuxue.0'), [this.percent]);
}
takeEffect(owner: BattleRole): void {
const dmg = Math.ceil(owner.attr.curHp * (this.percent / 100) * this.layer);
const reducPercent = callReducPercent(owner.attr.def + owner.extraAttr.def, owner.attr.lv); //目标防御提供的减伤比例
const dmg = Math.ceil(owner.attr.curHp * (this.percent / 100) * this.layer * (1 - reducPercent));
owner.addHp(-1 * dmg);
owner.battleLog(replace(t('skill.liuxue.1'), [this.layer, t(owner.type), dmg]));
owner.debuffLog(replace(t('skill.liuxue.1'), [this.layer, t(owner.type), dmg]));
}
}

4
src/config/skill/jewelry.ts

@ -42,7 +42,7 @@ export class CritFear extends SufPassiveSkill { @@ -42,7 +42,7 @@ export class CritFear extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const additional = Math.ceil((owner.atk * this.percent) / 100);
target.addHp(-1 * additional);
owner.battleLog(replace(t('skill.critFear.2'), [additional]));
owner.extraDmgLog(replace(t('skill.critFear.2'), [additional]));
}
}
//琉璃盘
@ -75,6 +75,6 @@ export class JHSY extends CounterSkill { @@ -75,6 +75,6 @@ export class JHSY extends CounterSkill {
const reflected = Math.ceil((target.baseDmg * this.percent) / 100);
target.addHp(-1 * reflected);
const log = replace(t('skill.JHSY.2'), [t(owner.type), reflected]);
owner.battleLog(log);
owner.extraDmgLog(log);
}
}

16
src/config/skill/neck.ts

@ -19,7 +19,7 @@ export class Duan extends SufPassiveSkill { @@ -19,7 +19,7 @@ export class Duan extends SufPassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
target.addHp(-1 * this.dmg);
owner.battleLog(replace(st('duan.2'), [this.hpPercent, this.dmg]));
owner.extraDmgLog(replace(st('duan.2'), [this.hpPercent, this.dmg]));
}
}
//红眼
@ -41,7 +41,7 @@ export class HongYan extends PrePassiveSkill { @@ -41,7 +41,7 @@ export class HongYan extends PrePassiveSkill {
if (this.trigger(owner, target)) {
const additional = Math.ceil((owner.atk * this.atkPercent) / 100);
target.addHp(-1 * additional);
owner.battleLog(replace(st('hongyan.2'), [this.hpPercent, additional]));
owner.extraDmgLog(replace(st('hongyan.2'), [this.hpPercent, additional]));
}
}
}
@ -61,14 +61,14 @@ export class ShaYi extends SufPassiveSkill { @@ -61,14 +61,14 @@ export class ShaYi extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const shayi = new BaseAtkPercentBuff(this.name, this.atkPercent, 9999, this.maxLayer);
owner.putBuff(shayi, this.retains);
owner.battleLog(replace(st('shayi.2'), [shayi.layer]));
owner.gainLog(replace(st('shayi.2'), [shayi.layer]));
}
onAtked(owner: BattleRole, target: BattleRole): void {
if (target.crit) {
const shayi = new BaseAtkPercentBuff(this.name, this.atkPercent, 9999, this.maxLayer);
shayi.layer = -1 * this.reduc;
owner.putBuff(shayi, this.retains);
owner.battleLog(replace(st('shayi.3'), [this.reduc]));
owner.debuffLog(replace(st('shayi.3'), [this.reduc]));
}
}
}
@ -88,7 +88,7 @@ export class NuMu extends CounterSkill { @@ -88,7 +88,7 @@ export class NuMu extends CounterSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const numu = new BaseAtkPercentBuff(this.name, this.atkPercent, 9999, this.maxLayer);
owner.putBuff(numu);
owner.battleLog(replace(st('numu.2'), [numu.layer]));
owner.gainLog(replace(st('numu.2'), [numu.layer]));
}
}
//龙腾
@ -109,7 +109,7 @@ export class LongTeng extends CounterSkill { @@ -109,7 +109,7 @@ export class LongTeng extends CounterSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const shield = Math.ceil((owner.attr.hp * this.shieldPercentOfHp) / 100);
owner.shield += shield;
owner.battleLog(replace(st('longteng.2'), [shield]));
owner.gainLog(replace(st('longteng.2'), [shield]));
}
}
//幸运数字
@ -121,7 +121,7 @@ export class XingYunShuZi extends SufPassiveSkill { @@ -121,7 +121,7 @@ export class XingYunShuZi extends SufPassiveSkill {
}
beforeBattle(owner: BattleRole, target: BattleRole): void {
this.num = Math.ceil(Math.random() * 9);
owner.battleLog(replace(st('xingyunshuzi.2'), [t(owner.type), this.num]));
owner.gainLog(replace(st('xingyunshuzi.2'), [t(owner.type), this.num]));
}
trigger(owner: BattleRole, target: BattleRole): boolean {
return this.num > 0 && owner.dmg % 10 == this.num;
@ -129,6 +129,6 @@ export class XingYunShuZi extends SufPassiveSkill { @@ -129,6 +129,6 @@ export class XingYunShuZi extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const dmg = owner.dmg * this.num;
target.addHp(-1 * dmg);
owner.battleLog(replace(st('xingyunshuzi.3'), [t(target.type), dmg]));
owner.extraDmgLog(replace(st('xingyunshuzi.3'), [t(target.type), dmg]));
}
}

4
src/config/skill/pants.ts

@ -31,7 +31,7 @@ export class FuRenBiHu extends PrePassiveSkill { @@ -31,7 +31,7 @@ export class FuRenBiHu extends PrePassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
owner.extraAttr.dmgReduc = this.dmgReduc;
owner.battleLog(replace(t('skill.furenbihu.2'), [this.hpPercent, this.dmgReduc]));
owner.gainLog(replace(t('skill.furenbihu.2'), [this.hpPercent, this.dmgReduc]));
}
}
//灵感
@ -62,7 +62,7 @@ export class WanKang extends CounterSkill { @@ -62,7 +62,7 @@ export class WanKang extends CounterSkill {
const max = Math.ceil((owner.attr.hp * this.hpPercnet) / 100);
reflected > max && (reflected = max);
target.addHp(-1 * reflected);
owner.battleLog(replace(t('skill.wankang.2'), [t(owner.type), reflected]));
owner.extraDmgLog(replace(t('skill.wankang.2'), [t(owner.type), reflected]));
}
}
//五味

14
src/config/skill/ring.ts

@ -36,7 +36,7 @@ export class JinGangZhuo extends SufPassiveSkill { @@ -36,7 +36,7 @@ export class JinGangZhuo extends SufPassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
target.putBuff(new ControlBuff(this.name, this.last));
owner.battleLog(replace(t('skill.jinggangzhuo.2'), [this.last]));
owner.extraDmgLog(replace(t('skill.jinggangzhuo.2'), [this.last]));
}
}
@ -56,10 +56,10 @@ export class FengXie extends SufPassiveSkill { @@ -56,10 +56,10 @@ export class FengXie extends SufPassiveSkill {
const fengxie = new CritDmgBuff(this.name, this.critDmg, 9999, this.maxLayer);
if (owner.crit) {
owner.putBuff(fengxie);
owner.battleLog(replace(t('skill.fengxie.2'), [fengxie.layer]));
owner.gainLog(replace(t('skill.fengxie.2'), [fengxie.layer]));
} else {
owner.attackBuff.delete(this.name);
owner.battleLog(t('skill.fengxie.3'));
owner.debuffLog(t('skill.fengxie.3'));
}
}
}
@ -79,7 +79,7 @@ export class ShiZhong extends CounterSkill { @@ -79,7 +79,7 @@ export class ShiZhong extends CounterSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const shizhong = new CritDmgReducBuff(this.name, this.critDmgReduc, 9999, this.maxLayer);
owner.putBuff(shizhong);
owner.battleLog(replace(t('skill.shizhong.2'), [shizhong.layer]));
owner.gainLog(replace(t('skill.shizhong.2'), [shizhong.layer]));
}
}
@ -96,7 +96,7 @@ export class ShenShang extends SufPassiveSkill { @@ -96,7 +96,7 @@ export class ShenShang extends SufPassiveSkill {
}
takeEffect(owner: BattleRole, target: BattleRole): void {
owner.addHp(this.hp);
owner.battleLog(replace(t('skill.shenshang.2'), [this.hp]));
owner.gainLog(replace(t('skill.shenshang.2'), [this.hp]));
}
}
@ -113,12 +113,12 @@ export class TongJueFanJi extends CounterSkill { @@ -113,12 +113,12 @@ export class TongJueFanJi extends CounterSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
if (!owner.action) {
const log = replace(t('skill.tongjuefanji.3'), [t(owner.type)]);
owner.battleLog(log);
owner.debuffLog(log);
return;
}
owner.skillPercent = this.percent;
owner.callDmg(target);
target.addHp(-1 * owner.dmg);
owner.battleLog(replace(t('skill.tongjuefanji.2'), [owner.dmg]));
owner.atteckLog(replace(t('skill.tongjuefanji.2'), [t(target.type), owner.dmg]));
}
}

14
src/config/skill/weapon.ts

@ -21,7 +21,7 @@ export class IceBlade extends SufPassiveSkill { @@ -21,7 +21,7 @@ export class IceBlade extends SufPassiveSkill {
const additional = Math.ceil((owner.atk * this.percent) / 100);
target.addHp(-1 * additional);
target.putBuff(new ControlBuff(this.name, this.last));
owner.battleLog(replace(st('iceBlade.2'), [additional, t(target.type), this.last]));
owner.extraDmgLog(replace(st('iceBlade.2'), [additional, t(target.type), this.last]));
}
}
//见红
@ -37,7 +37,7 @@ export class SeeRed extends ActionSkill { @@ -37,7 +37,7 @@ export class SeeRed extends ActionSkill {
owner.skillPercent = 0;
const liuxue = new LiuXue(this.layer, this.last);
target.putBuff(liuxue);
owner.battleLog(replace(st('user'), [t(owner.type), st(this.name + '.0')]) + replace(st('seeRed.1'), [this.layer, this.last]));
owner.extraDmgLog(replace(st('user'), [t(owner.type), st(this.name + '.0')]) + replace(st('seeRed.1'), [this.layer, this.last]));
}
}
//鳍刺
@ -55,7 +55,7 @@ export class QiCi extends SufPassiveSkill { @@ -55,7 +55,7 @@ export class QiCi extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const liuxue = new LiuXue(this.layer, this.last);
target.putBuff(liuxue);
owner.battleLog(replace(st('qici.2'), [t(target.type), this.layer, this.last]));
owner.extraDmgLog(replace(st('qici.2'), [t(target.type), this.layer, this.last]));
}
}
//暴虐
@ -72,7 +72,7 @@ export class BaoNue extends SufPassiveSkill { @@ -72,7 +72,7 @@ export class BaoNue extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const liuxue = new LiuXue(9999, this.last);
target.putBuff(liuxue);
owner.battleLog(replace(st('baonue.2'), [t(target.type), this.last]));
owner.extraDmgLog(replace(st('baonue.2'), [t(target.type), this.last]));
}
}
//扎心
@ -100,7 +100,7 @@ export class AoZhiDu extends SufPassiveSkill { @@ -100,7 +100,7 @@ export class AoZhiDu extends SufPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const aozhidu = new KuiLan('kuilan', this.last);
target.putBuff(aozhidu);
owner.battleLog(replace(st('aozhidu.2'), [t(target.type), this.last]));
owner.extraDmgLog(replace(st('aozhidu.2'), [t(target.type), this.last]));
}
}
//十九叉
@ -119,7 +119,7 @@ export class ShiJiuCha extends SufPassiveSkill { @@ -119,7 +119,7 @@ export class ShiJiuCha extends SufPassiveSkill {
if (this.cout >= 10) {
this.cout = 0;
const dmg = owner.dmg * this.times;
owner.battleLog(replace(st('shijiucha.2'), [t(owner.type), dmg]));
owner.extraDmgLog(replace(st('shijiucha.2'), [t(owner.type), dmg]));
}
}
}
@ -134,7 +134,7 @@ export class JianQiDongSiFang extends StartPassiveSkill { @@ -134,7 +134,7 @@ export class JianQiDongSiFang extends StartPassiveSkill {
takeEffect(owner: BattleRole, target: BattleRole): void {
const buff1 = new DmgPercentBuff(this.name, this.dmgPercent, 9999);
owner.putBuff(buff1);
const buff2 = new DmgReducBuff(this.name, this.dmgPercent, 9999);
const buff2 = new DmgReducBuff(this.name, this.dmgReduc, 9999);
owner.putBuff(buff2);
}
}

3
src/store/mutation.ts

@ -66,7 +66,8 @@ export const add_bootys = (state, bootys) => { @@ -66,7 +66,8 @@ export const add_bootys = (state, bootys) => {
set_sys_info(state, { msg: t('getCoins') + coins, type: 'booty', equips: equips });
equips.forEach((equip) => {
const idx = getArrayEmptyIdx(state.grid);
if (state.autoSell.includes(equip.quality.quality) || idx == -1) {
const quality = equip.quality.extraQuality || equip.quality.quality;
if (state.autoSell.includes(quality) || idx == -1) {
const coins = conisOfsell(equip);
add_player_coins(state, coins);
set_sys_info(state, { msg: t('autoSell.2') + t('getCoins') + coins, type: 'booty' });

2
src/store/state.ts

@ -7,6 +7,7 @@ export default { @@ -7,6 +7,7 @@ export default {
{ type: 'win', msg: t('welcome.0') },
{ type: 'win', msg: t('welcome.1') },
],
battleLog: 1, //是否显示战斗日志
mobile: window.innerWidth < 768,
curMenu: null,
equipTip: {
@ -36,4 +37,5 @@ export default { @@ -36,4 +37,5 @@ export default {
upward: true,
},
experiential: false,
showLogin: false,
};

7
src/tool/IndexedDB.ts

@ -3,8 +3,10 @@ import { deepCopy } from './caller'; @@ -3,8 +3,10 @@ import { deepCopy } from './caller';
const db_name = 'transmigration_game';
export const store_name_archive = 'archive';
export const key_name_archive = 'version';
export const store_name_config = 'config';
export const key_name_config = 'type';
const version = 1;
const version = 2;
let db;
/**
*
@ -45,6 +47,9 @@ const createStore = () => { @@ -45,6 +47,9 @@ const createStore = () => {
// 创建索引,在后面查询数据的时候可以根据索引查
// objectStore.createIndex(index_name_equip, index_name_equip, { unique: false });
}
if (!db.objectStoreNames.contains(store_name_config)) {
db.createObjectStore(store_name_config, { keyPath: key_name_config });
}
};
await openDB();

3
src/tool/caller/attribute.ts

@ -48,7 +48,8 @@ export const callPlayerAttribute = (player: Player, base: any) => { @@ -48,7 +48,8 @@ export const callPlayerAttribute = (player: Player, base: any) => {
attribute.dps = Math.ceil((1 - crit + crit * critdmg) * atk * (1 + dmgPercent));
//计算减伤比例
attribute.reducPercent = callReducPercent(attribute.def, player.lv);
player.attribute = attribute;
player.attribute.copy(attribute);
};
/**

21
src/tool/caller/battle.ts

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
import { Equip, Skills, Monster, Attribute, Player } from '@/config';
import { Equip, Skills, Monster, Attribute, Player, battle_msg_types } from '@/config';
import { randonBootyEquip, deepCopy, replace, callReducPercent, callDmgReduc, callDmgPercent } from '@/tool';
import i18n from '@/config/i18n';
const { t } = i18n;
@ -99,8 +99,21 @@ export class BattleRole { @@ -99,8 +99,21 @@ export class BattleRole {
this.initTmp();
};
battleLog = (log: string) => {
this.commit('set_sys_info', { type: 'battle', msg: log });
atteckLog = (log: string) => {
const type = (this.crit ? battle_msg_types.crit : battle_msg_types.attack) + '_' + this.type;
this.commit('set_sys_info', { type: type, msg: log });
};
gainLog = (log: string) => {
const type = battle_msg_types.gain + '_' + this.type;
this.commit('set_sys_info', { type: type, msg: log });
};
debuffLog = (log: string) => {
const type = battle_msg_types.debuff + '_' + this.type;
this.commit('set_sys_info', { type: type, msg: log });
};
extraDmgLog = (log: string) => {
const type = battle_msg_types.extra + '_' + this.type;
this.commit('set_sys_info', { type: type, msg: log });
};
addHp = (hp: number) => {
@ -152,7 +165,7 @@ export class BattleRole { @@ -152,7 +165,7 @@ export class BattleRole {
const crit = attr.crit + extra.crit - target.attr.critAvoid - target.extraAttr.critAvoid; //最终暴击率
this.crit = Math.random() < crit / 100;
if (this.crit) {
let critDmg = attr.critDmg + extra.critDmg - target.attr.critDmgReduc - target.extraAttr.critDmg; //目标最终承受暴击伤害
let critDmg = attr.critDmg + extra.critDmg - target.attr.critDmgReduc - target.extraAttr.critDmgReduc; //目标最终承受暴击伤害
critDmg = critDmg < 100 ? 100 : critDmg; //暴击伤害不低于100%
this.baseDmg *= critDmg / 100; //暴击时目标承受伤害
}

4
src/tool/crypot.ts

@ -39,3 +39,7 @@ export const AES_CBC_DECRYPT = (textBase64, secretKey) => { @@ -39,3 +39,7 @@ export const AES_CBC_DECRYPT = (textBase64, secretKey) => {
});
return CryptoJS.enc.Utf8.stringify(decrypt);
};
export const MD5 = (str) => {
return CryptoJS.MD5(str).toString().toUpperCase();
};

2
src/tool/random.ts

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@
import { difficultys, Categorys, qualitys, extra_quality, extra_quality_rate, extra_quality_lv } from '@/config';
import * as Equips from '@/config/equips';
const types = ['weapon', 'arrmor', 'neck', 'ring', 'jewelry', 'bracers', 'pants', 'shoes'];
const types = ['weapon', 'armor', 'neck', 'ring', 'jewelry', 'bracers', 'pants', 'shoes'];
const normal: Categorys[] = new Array();
const uniques: Categorys[] = new Array();
const colorfuls: Categorys[] = new Array();

69
src/views/archive.vue

@ -3,16 +3,20 @@ @@ -3,16 +3,20 @@
<img class="menu-img" :src="menu_icons.exportGame" @click="showMenu">
</Tooltip>
<Dialog :title="t('archive.0')" v-model="showArchive" top="15%" left='8%'>
<Dialog :title="t('archive.0')" v-model="showArchive" top="4rem" left='8%' @close="state.curMenu = null">
<div class="archive">
<span class="tip">* {{ t('archive.1') }}</span>
<textarea class="textarea" v-model="archive"></textarea>
</div>
<div class="footer">
<button class="button" @click="copyArchive">{{ t('copyArchive.0') }}</button>
<button class="button" @click="copyArchive(archive)">{{ t('copyArchive.0') }}</button>
<button class="button" @click="pasteArchive">{{ t('pasteArchive.0') }}</button>
<button class="button" @click="importArchive">{{ t('importArchive.0') }}</button>
</div>
<div class="footer">
<button class="button" @click="uploadArchive">{{ t('uploadArchive') }}</button>
<button class="button" @click="downArchive">{{ t('downArchive') }}</button>
</div>
</Dialog>
</template>
@ -23,8 +27,8 @@ import { computed, onMounted, ref, onBeforeUnmount } from "vue"; @@ -23,8 +27,8 @@ import { computed, onMounted, ref, onBeforeUnmount } from "vue";
import { useI18n } from "vue3-i18n";
import { Tooltip, Dialog } from "@/components"
import { menu_icons } from "@/config";
import { getArchive, AES_CBC_ENCRYPT, AES_CBC_DECRYPT, checkImportArchive, saveArchive, replace, archive_version } from "@/tool";
import { getArchive, AES_CBC_ENCRYPT, AES_CBC_DECRYPT, checkImportArchive, saveArchive, replace, archive_version, MD5 } from "@/tool";
import * as API from "@/api";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
@ -34,6 +38,15 @@ const showArchive = computed(() => { @@ -34,6 +38,15 @@ const showArchive = computed(() => {
const archive = ref('');
const key = 'KUf4hM5rThssysJhcRFCfxLR8Imihjl0eMsyhh1M7Wk';
let timeOut = 0;
const strengthenLv = computed(() => {
const player = state.playerAttribute;
const equips = [player.weapon, player.armor, player.neck, player.ring, player.jewelry, player.pants, player.shoes, player.bracers];
let lv = 0;
equips.forEach(equip => {
equip && (lv += equip.strengthenLv)
})
return lv;
});
const showMenu = () => {
if (showArchive.value) {
@ -46,9 +59,9 @@ const showMenu = () => { @@ -46,9 +59,9 @@ const showMenu = () => {
}
}
const copyArchive = () => {
const copyArchive = (archive) => {
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(archive.value).then(() => {
navigator.clipboard.writeText(archive).then(() => {
commit('set_sys_info', { msg: t('copyArchive.1'), type: 'win' })
showMenu();
}).catch(() => {
@ -56,7 +69,7 @@ const copyArchive = () => { @@ -56,7 +69,7 @@ const copyArchive = () => {
});
} else {
const textField = document.createElement("textarea");
textField.innerText = archive.value;
textField.innerText = archive;
document.body.appendChild(textField);
textField.select();
document.execCommand("copy");
@ -66,12 +79,44 @@ const copyArchive = () => { @@ -66,12 +79,44 @@ const copyArchive = () => {
}
}
const uploadArchive = () => {
API.getUser().then(user => {
if (user) {
const palyer = state.playerAttribute;
const data = { version: archive_version, lv: palyer.lv, coins: palyer.coins, strengthenLv: strengthenLv.value, archive: archive.value }
API.uploadArchive(data).then(rsp => rsp && showMenu());
} else {
state.showLogin = true;
}
});
}
const downArchive = () => {
API.getUser().then(user => {
if (user) {
API.downArchive({ version: archive_version }).then((rsp: any) => {
if (rsp) {
archive.value = rsp;
importArchive();
}
});
} else {
state.showLogin = true;
}
});
}
const pasteArchive = () => {
navigator.clipboard.readText().then((text) => {
archive.value = text;
commit('set_sys_info', { msg: t('pasteArchive.1'), type: 'win' })
}, () => {
commit('set_sys_info', { msg: t('pasteArchive.2'), type: 'waring' })
const name: any = 'clipboard-read';
navigator.permissions.query({ name: name }).then(result => {
if (result.state === 'granted') {
navigator.clipboard.readText().then(text => {
archive.value = text;
commit('set_sys_info', { msg: t('pasteArchive.1'), type: 'win' })
});
} else {
commit('set_sys_info', { msg: t('pasteArchive.2'), type: 'waring' })
}
});
}

4
src/views/backpack/auto-sell.vue

@ -21,6 +21,8 @@ @@ -21,6 +21,8 @@
<label :for="qualitys[3]">{{ t('quality.' + qualitys[3]) }}</label>
<input type="checkbox" v-model="autoSell" :value="qualitys[4]" :id="qualitys[4]">
<label :for="qualitys[4]">{{ t('quality.' + qualitys[4]) }}</label>
<input type="checkbox" v-model="autoSell" :value="qualitys[5]" :id="qualitys[5]">
<label :for="qualitys[5]">{{ t('quality.' + qualitys[5]) }}</label>
</div>
</div>
</span>
@ -30,7 +32,7 @@ @@ -30,7 +32,7 @@
import { useStore } from "vuex";
import { ref, watch } from "vue";
import { useI18n } from "vue3-i18n";
import { qualitys, menu_icons } from "@/config";
import { qualitys, extra_quality, menu_icons } from "@/config";
import { deepCopy } from "@/tool";
const { t } = useI18n();

2
src/views/backpack/backpack.vue

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<img class="menu-img" :src="menu_icons.backpack" @click="showMenu">
</Tooltip>
<Dialog :title="t('backpack')" v-model="show" top="4rem" left='8%'>
<Dialog :title="t('backpack')" v-model="show" top="4rem" left='8%' @close="state.curMenu = null">
<Player />
<Grid @openEquipMenu="openEquipMenu" />
</Dialog>

7
src/views/backpack/equip-menu.vue

@ -11,13 +11,13 @@ @@ -11,13 +11,13 @@
</Dialog>
<Dialog :title="t('strengthen') + t('equip')" v-model="showStrengthen" top="5rem" left="2rem" padding="0" :z="11"
:obscured="true">
<Strengthen :equip="state.grid[index]" />
:obscured="true" @close="strengthen?.stopAuto()">
<Strengthen ref="strengthen" :equip="state.grid[index]" />
</Dialog>
<Dialog :title="t('equip') + t('inherited.0')" v-model="showInherited" :top="state.mobile ? '5rem' : '10rem'"
left="2rem" padding="0" :z="11" :obscured="true">
<Inherited :target="equip" :source="curEquip" @close="showInherited = false" />
<Inherited :target="equip" :source="curEquip" />
</Dialog>
</template>
@ -47,6 +47,7 @@ const curEquip = computed(() => { @@ -47,6 +47,7 @@ const curEquip = computed(() => {
}
return state.playerAttribute[equip.value.type];
})
const strengthen = ref();
defineExpose({ open })

27
src/views/backpack/grid.vue

@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
@touchstart="mobile.onTouchStart($event, [v, idx])" @touchmove="mobile.onTouchMove"
@touchend="mobile.onTouchEnd" @dblclick="commit('close_equip_tip'); dispatch('useEquip', idx);"
@mouseover="commit('show_equip_tip', { equip: v, compare: true, e: $event })"
@mouseleave="commit('close_equip_tip')">
@mouseleave="commit('close_equip_tip')" @click="clickGrid($event, v)">
<EquipIcon :equip="v" />
<div class="equip-lock" v-if="v.locked">
<img :src="lock_icon">
@ -62,15 +62,16 @@ const itemNum = computed(() => { @@ -62,15 +62,16 @@ const itemNum = computed(() => {
});
const neaten = () => {
const tem = new Array(grid.value.length);
let i = 0;
grid.value.forEach((item) => {
if (item) {
tem[i] = item
i++;
}
})
commit("set_backpack", tem);
grid.value.sort((a, b) => {
if (!a && !b) return 0;
else if (!a) return 1;
else if (!b) return -1;
let tmp = b.type.localeCompare(a.type, 'en');
if (tmp != 0) return tmp;
tmp = b.base.name.localeCompare(a.base.name, 'en');
if (tmp != 0) return tmp;
return b.lv - a.lv;
});
}
const sellAll = () => {
state.grid.forEach((item, index) => {
@ -107,6 +108,12 @@ const confirmAddGrid = () => { @@ -107,6 +108,12 @@ const confirmAddGrid = () => {
}
}
const clickGrid = (e, equip) => {
if (e.altKey && equip) {
equip.locked = !equip.locked;
}
}
onMounted(() => { });
</script>
<style lang="scss" scoped>

8
src/views/backpack/inherited.vue

@ -77,6 +77,7 @@ import { computed, onMounted, ref } from "vue"; @@ -77,6 +77,7 @@ import { computed, onMounted, ref } from "vue";
import { useI18n } from "vue3-i18n";
import { strengthenAvgCoins, strengthenValue } from "@/tool";
import { EquipIcon, Confirm } from "@/components";
import { qualitys } from "@/config";
const { t } = useI18n();
@ -119,7 +120,12 @@ const confirmInherited = () => { @@ -119,7 +120,12 @@ const confirmInherited = () => {
emit('close');
}
onMounted(() => { });
onMounted(() => {
const need = strengthenAvgCoins(100, 13, qualitys[5]);
const used = strengthenAvgCoins(1, 13, qualitys[0]);
console.log(need - used);
});
</script>
<style lang="scss" scoped>
.inherited {

16
src/views/backpack/player.vue

@ -89,6 +89,14 @@ onMounted(() => { }); @@ -89,6 +89,14 @@ onMounted(() => { });
text-align: start;
}
.label,
.value {
div {
line-height: 1.5rem;
height: 1.5rem;
}
}
}
.equips {
@ -181,6 +189,14 @@ onMounted(() => { }); @@ -181,6 +189,14 @@ onMounted(() => { });
text-align: start;
}
.label,
.value {
div {
line-height: 1.2rem;
height: 1.2rem;
}
}
}
.equips {

2
src/views/backpack/strengthen.vue

@ -121,6 +121,8 @@ const stopAuto = () => { @@ -121,6 +121,8 @@ const stopAuto = () => {
auto.value = false;
};
defineExpose({ stopAuto })
onMounted(() => { });
</script>
<style lang="scss" scoped>

8
src/views/dungeon/battle.vue

@ -81,12 +81,14 @@ const exploreDungeon = (monsterIdx) => { @@ -81,12 +81,14 @@ const exploreDungeon = (monsterIdx) => {
return;
} else if (dungeon.difficulty == difficultys[4]) {
//
commit('set_player_layer', dungeon.layer);
if (dungeon.layer > layer.value) {
commit('set_player_layer', dungeon.layer);
}
commit('add_player_curhp', state.playerAttribute.attribute.hp);
}
if (state.battle.repeat) {
if (dungeon.difficulty == difficultys[4] && state.battle.upward) {
dungeon.setLayer(layer.value + 1);
dungeon.setLayer(dungeon.layer + 1);
}
playerMove(0, 0);
} else {
@ -123,7 +125,7 @@ watch(() => state.playerAttribute.attribute, (n) => { @@ -123,7 +125,7 @@ watch(() => state.playerAttribute.attribute, (n) => {
const battleWithMonster = (monster) => {
return new Promise((resolve, reject) => {
const battleTime = Math.ceil(player_battle_time * 100 / (100 + state.baseAttribute.battleSpeed))
const lvOrLayer = props.dungeon?.difficulty == 'dami' ? state.playerAttribute.layer + t('layer') : 'lv' + monster.lv;
const lvOrLayer = props.dungeon?.difficulty == 'dami' ? props.dungeon.layer + t('layer') : 'lv' + monster.lv;
const monsterName = t('difficulty.' + props.dungeon?.difficulty) + t(monster.type);
const msg = replace(t('battle'), [lvOrLayer, monsterName])
commit("set_sys_info", { msg: msg, type: 'battle' });

18
src/views/dungeon/dungeonTips.vue

@ -5,7 +5,10 @@ @@ -5,7 +5,10 @@
{{ t('dungeonTips.0') }}:
<span v-if="show_lv_df.includes(dungeon.difficulty)">lv_{{ dungeon.lv }}</span>
{{ t('difficulty.' + dungeon.difficulty) }}
<span v-if="dungeon.difficulty == 'dami'">({{ layer }}{{ t('layer') }})</span>
<select v-if="dungeon.difficulty == 'dami'" class="select" v-model="layer1">
<option v-for="i in layer" :value="i">{{ i }}{{ t('layer') }}</option>
</select>
<!-- <span >({{ layer }}{{ t('layer') }})</span> -->
</div>
<div class="tip">
<p>- {{ t('dungeonTips.2') }}</p>
@ -36,7 +39,7 @@ @@ -36,7 +39,7 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref, computed } from "vue";
import { reactive, onMounted, ref, computed, watch } from "vue";
import { useI18n } from "vue3-i18n";
import { close_icon, qualitys, show_lv_df } from "@/config";
@ -63,6 +66,12 @@ const battle = computed(() => { @@ -63,6 +66,12 @@ const battle = computed(() => {
const layer = computed(() => {
return state.playerAttribute.layer;
})
const layer1 = ref(layer.value)
watch(() => layer1.value, (n) => {
if (n) {
props.dungeon.setLayer(n);
}
})
const props = defineProps({
dungeon: {
@ -96,6 +105,11 @@ onMounted(() => { }); @@ -96,6 +105,11 @@ onMounted(() => { });
font-size: 1.2rem;
}
.select {
font-size: 1.1rem;
background-color: rgba(0, 0, 0, 0.6);
}
.tip {
padding-left: 0.4rem;

2
src/views/illustrated/illustrated.vue

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<img class="menu-img" :src="menu_icons.illustrated" @click="showMenu">
</Tooltip>
<Drawer :title="t('illustrated.0')" v-model="showIllustrated">
<Drawer :title="t('illustrated.0')" v-model="showIllustrated" :width="state.mobile ? '100%' : ''" @close="state.curMenu = null">
<Tabs :tabs="tabs">
<tab v-for="item in tabs" :name="item.name">
<Equips :type="item.name" quality="colorful" extraQuality="taigu" :samples="taigu[item.name]" />

4
src/views/index.vue

@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
<Menu />
</div>
<EquipTips />
<Login />
</template>
<script lang="ts" setup>
@ -16,9 +17,12 @@ import { useI18n } from "vue3-i18n"; @@ -16,9 +17,12 @@ import { useI18n } from "vue3-i18n";
import Message from "./message";
import Menu from "./menu.vue";
import { EquipTips } from "@/components";
import { setCommit } from "@/api";
import Login from "./login.vue";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
setCommit(commit);
const playFlag = ref(false);
const playBackgound = () => {

64
src/views/login.vue

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
<template>
<Dialog :title="t('login.0')" v-model="state.showLogin" :top="state.mobile ? '5rem' : '10rem'"
:left="state.mobile ? '2rem' : '10rem'" padding="0" :z="50" :obscured="true">
<div class="login">
<div class="item">
<div class="label">{{ t('login.1') }}: </div>
<input type="text" v-model="user.username"><br>
</div>
<div class="item">
<div class="label">{{ t('login.2') }}: </div>
<input type="password" v-model="user.password"><br>
</div>
<button class="button" @click="login">{{ t('login.3') }}</button>
</div>
</Dialog>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { reactive, onMounted, ref, computed } from "vue";
import { useI18n } from "vue3-i18n";
import { Dialog } from "@/components";
import { deepCopy, MD5 } from "@/tool";
import { loginOrRegister } from "@/api";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const user = reactive({
username: '',
password: '',
})
const login = () => {
const username = user.username;
const password = user.password;
if (!username) {
commit('set_sys_info', { msg: t('login.4'), type: 'warning' })
return;
}
if (!password) {
commit('set_sys_info', { msg: t('login.5'), type: 'warning' })
return;
}
const param = { username: username, password: MD5(password) };
loginOrRegister(param).then(rsp => {
rsp && (state.showLogin = false);
})
}
onMounted(() => { });
</script>
<style lang="scss" scoped>
.login {
padding: 1rem;
.item {
padding: 0.5rem 0;
.label {
text-align: left;
}
}
}
</style>

5
src/views/menu.vue

@ -6,9 +6,10 @@ @@ -6,9 +6,10 @@
<SaveGame />
<Archive />
<Dungeon />
<Music />
<!-- <Music /> -->
<Illustrated />
<Version />
<Setting />
</div>
</template>
@ -19,13 +20,13 @@ import { useI18n } from "vue3-i18n"; @@ -19,13 +20,13 @@ import { useI18n } from "vue3-i18n";
import Backpack from "./backpack";
import Shop from "./shop";
import Dungeon from './dungeon';
import Reborn from "./reborn";
import Point from "./point";
import SaveGame from "./save-game.vue";
import Archive from "./archive.vue";
import Music from "./music.vue";
import Illustrated from "./illustrated";
import Version from "./version";
import Setting from "./setting.vue";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();

67
src/views/message/sys-info.vue

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
<template>
<div class='sysInfo' ref="sysInfo">
<div :class="['info', v.type]" v-for="(v, k) in state.sysInfo" :key="k">
<div :class="['info', v.type]" v-for="(v, k) in infos" :key="k">
<span>{{ t('sys') }}</span>
<i class="time" v-if="v.time">({{ v.time }})</i>
<span class="msg">{{ v.msg }}</span>
@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
<script lang="ts" setup>
import { useStore } from "vuex";
import { watch, nextTick, onMounted, ref } from "vue";
import { watch, nextTick, onMounted, ref, computed } from "vue";
import { useI18n } from "vue3-i18n";
import { qualitys } from "@/config";
import { Drawer, Tooltip } from "@/components";
@ -32,6 +32,15 @@ import Bouts from "./bouts.vue"; @@ -32,6 +32,15 @@ import Bouts from "./bouts.vue";
const { t } = useI18n();
const { state, commit, dispatch } = useStore();
const infos = computed(() => {
if (state.battleLog === 1) {
return state.sysInfo;
} else {
return state.sysInfo.filter(info => {
return info.type.indexOf('_') === -1;
})
}
})
const sysInfo = ref();
const showBouts = ref(false)
const bouts = ref<any>([])
@ -71,14 +80,11 @@ a { @@ -71,14 +80,11 @@ a {
margin-left: 0.3rem;
}
.warning>.msg {
color: #f90202;
}
.battle>.msg {
color: #de8618;
}
.win>.msg {
color: #24c4de;
}
@ -92,6 +98,48 @@ a { @@ -92,6 +98,48 @@ a {
padding-left: 0.3rem;
}
.attack_player>.msg,
.extra_player>.msg {
color: #B0E0E6;
}
.crit_player>.msg {
color: #FFD700;
font-size: 1.15rem;
}
.gain_player>.msg {
color: #2df805;
}
.debuff_player>.msg {
color: #489e0291;
}
.crit_monster,
.crit_boss>.msg {
color: #ff0505;
font-size: 1.15rem;
}
.attack_monster,
.attack_boss>.msg,
.extra_monster>.msg,
.extra_boss>.msg {
color: #ff0505;
}
.gain_monster,
.gain_boss>.msg {
color: #489e0291;
}
.debuff_monster,
.debuff_boss>.msg {
color: #2df805;
}
@media only screen and (max-width: 768px) {
.sysInfo {
font-size: 0.8rem;
@ -101,5 +149,12 @@ a { @@ -101,5 +149,12 @@ a {
font-size: 0.6rem;
}
.crit_player,
.crit_monster,
.crit_boss>.msg {
font-size: 1.1rem;
}
}
</style>

60
src/views/point/point.vue

@ -3,7 +3,8 @@ @@ -3,7 +3,8 @@
<img class="menu-img" :src="menu_icons.reborn" @click="showMenu">
</Tooltip>
<Dialog :title="t('menu')" v-model="showReborn" top="4rem" :left="state.mobile ? '4%' : '8%'" padding="0.7rem">
<Dialog :title="t('menu')" v-model="showReborn" top="4rem" :left="state.mobile ? '4%' : '8%'" padding="0.7rem"
@close="state.curMenu = null">
<div class="message">
<div class="tips">
<p>- {{ t('desc.0') }}</p>
@ -213,4 +214,61 @@ onBeforeUnmount(() => { @@ -213,4 +214,61 @@ onBeforeUnmount(() => {
}
}
@media only screen and (max-width: 768px) {
.message {
padding-bottom: 0.5rem;
p {
margin: 0.5rem;
}
.tips {
padding-left: 0.8rem;
}
.btn-div {
padding: 0rem;
padding-right: 1rem;
}
}
.points {
padding: 0.1rem;
width: 23.5rem;
.info {
padding: 0.2rem;
}
}
.attributes {
padding: 0.05rem 0;
}
.attribute {
padding: 0.2rem 0rem;
p {
span {
margin-left: 0.2rem;
}
}
.group {
input {
width: 4rem;
color: black;
height: 1.8rem;
font-size: 0.8rem;
}
}
}
}
</style>

135
src/views/setting.vue

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
<template>
<Tooltip :infos="[t('title')]" width="10rem">
<img class="menu-img" :src="menu_icons.settings" @click="showMenu">
</Tooltip>
<Dialog :title="t('title')" v-model="show" top="4rem" :left="state.mobile ? '4%' : '8%'" padding="0.7rem" :z="49"
@close="state.curMenu = null">
<div class="setting">
<div class="item">
<div class="label">{{ t('music.0') }}</div>
<div class="options">
<input type="radio" id="none" :value="0" v-model="settings.music"> {{ t('music.1') }}
<input type="radio" id="min" :value="0.01" v-model="settings.music"> {{ t('music.2') }}
<input type="radio" id="normal" :value="0.2" v-model="settings.music"> {{ t('music.3') }}
</div>
</div>
<div class="item">
<div class="label">{{ t('battle.0') }}</div>
<div class="options">
<input type="radio" :value="1" v-model="settings.battle"> {{ t('battle.1') }}
<input type="radio" :value="0" v-model="settings.battle"> {{ t('battle.2') }}
</div>
</div>
</div>
<div class="footer">
<button class="button" @click="saveSettings">{{ t('action.0') }}</button>
<button class="button" @click="showMenu">{{ t('action.1') }}</button>
</div>
</Dialog>
</template>
<script lang="ts" setup>
import { useStore } from "vuex";
import { computed, onBeforeUnmount, onMounted, reactive, ref } from "vue";
import { Tooltip, Dialog } from "@/components"
import { menu_icons } from "@/config";
import { createt } from "@/config/i18n";
import { store_name_config, key_name_config, getFromStore, insertToStore } from "@/tool";
const t = createt('setting.');
const { state, commit, dispatch } = useStore();
const show = computed(() => {
return state.curMenu == 'setting';
});
const settings = ref({
type: 'setting',
music: 0.01,
battle: 1
})
const saveSettings = () => {
insertToStore(store_name_config, settings.value);
set();
showMenu();
}
const set = () => {
dispatch('set_music_volume', settings.value.music);
state.battleLog = settings.value.battle;
}
const readSetting = () => {
getFromStore(store_name_config, settings.value.type).then((rsp: any) => {
if (rsp) {
settings.value = rsp
set();
};
});
}
const showMenu = () => {
state.curMenu = show.value ? null : 'setting';
}
const keydown = (e) => {
if (state.curMenu != null) {
return;
}
if (e.keyCode == 27 && !e.ctrlKey) {
setTimeout(() => {
showMenu();
}, 50);
}
}
onMounted(() => {
document.addEventListener('keydown', keydown, true)
readSetting();
});
onBeforeUnmount(() => {
document.removeEventListener('keydown', keydown)
})
</script>
<style lang="scss" scoped>
.setting {
width: 32rem;
font-size: 1rem;
padding-top: 1rem;
.label {
float: left;
width: 25%;
text-align: right;
}
.options {
float: right;
width: 73%;
text-align: left;
}
.item {
height: 2rem;
}
.footer {
padding-top: 1rem;
}
}
@media only screen and (max-width: 768px) {
.setting {
width: 23.5rem;
margin-top: 0.5rem;
font-size: 0.8rem;
.footer {
margin-top: 0.5rem;
}
}
}
</style>

2
src/views/shop/shop.vue

@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
<img class="menu-img" :src="menu_icons.shop" @click="showMenu">
</Tooltip>
<Dialog :title="t('shop')" v-model="showShop" top="20%" left='8%'>
<Dialog :title="t('shop')" v-model="showShop" top="4rem" left='8%' @close="state.curMenu = null">
<div class="coins">
{{ t('coins.0') }}:{{ coins }}
</div>

35
src/views/version/update-log.vue

@ -38,6 +38,41 @@ const hisVersions = [ @@ -38,6 +38,41 @@ const hisVersions = [
]
const updateLogs: any = [{
date: '2025-05-21', version: '1.0',
adjust: [
'流血伤害不再是真实伤害,受护甲减伤影响',
'修复武器青光被动异常减伤BUG',
'自动出售可勾选神话品质',
'新增系统设置,可设置完全无音乐和隐藏战斗信息',
],
bug: [
'修复一些UI显示BUG',
'修复鬼门甲被动BUG(预期提升200%,实际提升200倍)',
],
}, {
date: '2025-05-20', version: '1.0',
adjust: [
'一键整理增加排序功能',
'基础属性增加ROLL值百分百显示',
'新增Alt+左键快速锁定/解锁装备',
'新增挑战大秘境可选择层数',
],
bug: [
'修复普通副本怪物拥有暴伤减免属性BUG',
]
}, {
date: '2025-05-19', version: '1.0',
adjust: [
'战斗信息做颜色区分',
'新增上传/下载存档功能',
],
bug: [
'修复复制存按钮档无效BUG',
'修复不掉落护甲BUG,修复移动端两个UI显示BUG',
'修复背包界面属性对不齐BUG',
'修复自动强化开启后,点击右上角叉叉并不会停止自动强化BUG(导致你接下来选择哪个装备就会自动强化哪个装备)。',
]
}, {
date: '2025-05-17', version: '1.0',
adjust: [
'新增装备属性:伤害加成,伤害减免,暴击避免,爆伤减免,移动速度,转生属性副本行进速度更改为移动速度',

2
src/views/version/version.vue

@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
<img class="menu-img" :src="menu_icons.extras" @click="showMenu">
</Tooltip>
<Drawer v-model="showVersion" :width="state.mobile ? '100%' : '35%'">
<Drawer v-model="showVersion" :width="state.mobile ? '100%' : '35%'" @close="state.curMenu = null">
<UpdateLog />
</Drawer>

14
vue.config.js

@ -2,5 +2,17 @@ const { defineConfig } = require('@vue/cli-service'); @@ -2,5 +2,17 @@ const { defineConfig } = require('@vue/cli-service');
module.exports = defineConfig({
productionSourceMap: false,
transpileDependencies: true,
devServer: {
proxy: {
'/api': {
target: process.env.VUE_APP_BASE_URL,
// 允许跨域
changeOrigin: true,
ws: true,
pathRewrite: {
'^/api': '',
},
},
},
},
});

Loading…
Cancel
Save