蓝天资源网
当前位置:蓝天资源网 / 汇编逆向 / 正文

TapTap猛鬼宿舍 抖音躺平发育 修改各种功能教程

作者:忆笙发布时间:2022-01-23 00:00浏览数量:1046次评论数量:1次

猛鬼宿舍DIY

从抖音上看到了这个游戏,玩了一会还算不错,就是是单机,而且AI还挺弱智,开发团队刚开发的原因;不过我觉得这个类型还是蛮喜欢的

从TapTap叫猛鬼宿舍,在抖音叫躺平发育,都是一样的

从TapTap下载,要依靠TapTap启动。通过mt,最终在/data/com.taptap/virtual/data/app/目录下找到了apk安装包,然后提取了出来。但是主界面少了场外商店和皮肤,不知道为什么(后来不知怎么又有了)

jadx打开查看MainActivity没有东西,也搜不到任何字符串。正疑惑呢发现了一个类叫JSBridge,所以猜想这东西主要代码应该在js那。

于是解压搜索,找到了位于assets/cache/stand.alone.version/的文件6ab7299a

分析class i

首先看到的是各个局内道具的价格定义

// row49
class i {
    constructor() {
        (this._newBuildData = {
            at: [
                /* 花费金币,花费闪电,攻击力,攻击距离,升级前置条件 */
                ["笤帚炮台", 8, 0, 4, 4, ""],
                ["铲铲炮台", 16, 0, 8, 4.5, ""],
                ["鱼叉炮台", 32, 0, 16, 5, ""],
                ["喷射水枪", 64, 0, 32, 5.5, ""],
                ["高压水枪", 256, 0, 64, 6, "game_1"],
                ["气泡发射器", 512, 0, 128, 6.5, ""],
                ["魔力气泡机", 1024, 32, 256, 7, "game_2"],
                ["驱魔气泡机", 2048, 64, 512, 7.5, ""],
                ["初级激光器", 4096, 128, 1024, 8, "game_3"],
                ["恶魔激光器", 8192, 256, 2048, 8.5, "game_4"],
                ["圣光生成器", 16384, 512, 4096, 9, "game_5"],
                ["圣光发射器", 32768, 1024, 8192, 9.5, "game_6"],
                ["圣光炮台", 65536, 2048, 16384, 10, ""],
            ],
            bed: [
                /* 花费金币,花费闪电,金币产量,闪电产量,升级前置条件 */
                ["发霉小床", 0, 0, 1, 0, ""],
                ["湿冷小床", 25, 0, 2, 0, ""],
                ["破旧小床", 50, 0, 4, 0, "door_2"],
                ["简陋的床", 100, 0, 8, 0, ""],
                ["标准床铺", 200, 0, 16, 0, "door_5"],

具体属性猜测如下:

at: [
/* 炮台:花费金币,花费闪电,攻击力,攻击距离,升级前置条件 */],
bed: [
/* 床:花费金币,花费闪电,金币产量,闪电产量,升级前置条件 */],
door: [
    /* 门:花费金币,花费闪电,金币产量,未知,升级前置条件 */],
game: [
    /* 游戏机:花费金币,花费闪电,金币产量,闪电产量,升级前置条件 */],
mine: [
    /* 矿:花费金币,花费闪电,金币产量,闪电产量,升级前置条件 */],

此外还有一些特殊道具的花费

(this._newBuildData1 = {
    spell: ["符咒弹射器", 0, 64, 0, 0, ""],
    ice: ["冰箱", 0, 256, 0, 0, ""],
    entrapment: ["诱捕", 0, 512, 0, 0, ""],
    barb: ["倒刺", 0, 512, 0, 0, ""],
    guillotine: ["断头台", 0, 2048, 0, 0, ""],
    repair: ["维修台", 0, 64, 0, 0, ""],
    energyhood: ["能量罩", 0, 64, 0, 0, ""],
    smoney: ["取款机", 0, 128, 0, 0, ""],
    longrange: ["瞭望台", 0, 256, 0, 0, ""],
    particlea: ["粒子加速器", 0, 2048, 0, 0, ""],
    solenoid: ["电磁圈", 0, 2048, 0, 0, ""],
}),

我们可以在这里修改物品的属性,比如说攻击力,血量,购买花费金币闪电什么的。

再之后是商品的一些描述。

继续向下分析,是一些局内商店和局外商店可以购买的物品,

(this._basicBuildData = [
    ["at_1", "game_1", "repair_1"],
    ["mine_1", "mine_2", "mine_3", "mine_4"],
    ["spell_1", "energyhood_1", "smoney_1", "ice_1"],
    ["entrapment_1", "barb_1", "guillotine_1"],
    ["longrange_1", "particlea_1", "solenoid_1"],
]),
(this._ShopBuildData = [
    ["spell_1", "energyhood_1", "smoney_1", "ice_1"],
    ["entrapment_1", "barb_1", "guillotine_2", "repair_1"],
    ["longrange_1", "particlea_1", "solenoid_2"],
]),

再之后是皮肤图片加载,和局外商店的物品价格,标识为999的,则需要通过看视频来获得

(this._skin = { spell: "map/spellimg_0.png", energyhood: "map/energyhood_2.png", smoney: "map/money.png", entrapment: "map/entramentImage_1.png", guillotine: "map/guillotine_3.png", particlea: "map/particleaImg.png", solenoid: "map/solenoidimg_1.png" }),
(this._ShopBuildMoney = {
    repair: ["维修台", 10],
    spell: ["符咒弹射器", 20],
    smoney: ["取款机", 20],
    ice: ["冰箱", 30],
    entrapment: ["诱捕", 30],
    barb: ["倒刺", 50],
    energyhood: ["能量罩", 50],
    guillotine: ["断头台", 999],
    longrange: ["瞭望台", 30],
    particlea: ["粒子加速器", 100],
    solenoid: ["电磁圈", 999],
}),

这部分数据看不太懂是什么,应该是一些我没有用过的道具的属性buff

(this._AIPos = [
    [21, 22],
    [21, 23],
    [22, 22],
    [22, 23],
    [23, 22],
    [23, 23],
]),
(this._trollPos = [
    [22, 1],
    [41, 23],
    [21, 35],
    [1, 23],
]),
(this.AtBasePower = [1, 2, 4, 6, 14, 22.5, 40, 75]),
(this.bulletBuff = { 1: [0, 0, 0.01, 0.02, 0.03, 0.04, 0.05, 0.08], 2: [0, 0, 0, 0, 0, 0.5, 0.7, 1], 3: [0, 0, 1, 2, 3, 4, 5, 8] }),
(this.AtBuffEff = [
    [0, 0, 0, 0, 0, 0.01, 0.02, 0.04],
    [0, 0, 0, 0, 0, 0.01, 0.02, 0.04],
    [0, 0, 0, 0, 0, 0.01, 0.02, 0.04],
]);

之后便是一些get方法

class _

这个类里面有一些房间room的信息,判断游戏是否结束和开始,是否胜利,还有玩家数组,是否是mvp什么的,还有初始化玩家信息,和对玩家按金币和闪电进行冒泡排序;没啥需要修改的

class n

玩家的一些信息

constructor() {
    (this._key = "PlayerData"),
        (this._trollIndex = 0),
        (this.countI = 3),
        /* 皮肤最大数量 */
        (this.skinMaxNum = 6),
        /* 皮肤序号 */
        (this.skin = [0, 6, 2, 3, 4, 5]),
        /* 玩家的一些信息 */
        (this._data = {
            _playerSelectIndex: 0,
            /* 玩家拥有的皮肤数组 */ _playerSkin: [0],
            _win: 0,
            _lose: 0,
            _mvp: 0,
            _gold: 0,
            _task: 0,
            _taskOk: !1,
            _ysOK: !1,
            /* 道具数量 */ _blueprint: { spell: 1, ice: 1, entrapment: 1, barb: 1, guillotine: 1, repair: 10, energyhood: 1, smoney: 1, longrange: 1, particlea: 1, solenoid: 1 },
        }),
        (this._goldTextArr = []),
        this.Read();
}

这里可以修改初始化的道具数量,和皮肤数组

返回道具数量,直接改成定值10

GetBuileprintNum(t) {
    let e = this._data._blueprint[t];
    return null != e ? e : null;
}
// 改为
return 10;

class Y

局内道具判断

BuildOrUp(t) {
    let e = h.instance.game.GetRoomPR(y.instance.player.roomIndex),
        i = t.split("_"),
        s = h.instance.build.GetBuildData(i[0], parseInt(i[1]));
    if (0 == s[5].length || this.ReachConditions(s[5], y.instance.player.roomIndex))
        if (e.gold1 >= s[1] && e.gold2 >= s[2])
            if (((e.gold1 -= s[1]), (e.gold2 -= s[2]), null == this.clickBlock.blockC)) r.instance.Fire(r.instance.MAP_BUILD_NEW, this.clickBlock.x, this.clickBlock.y, t);
            else {
                let e = this.clickBlock.blockC.FindBlockInfo_Pos(this.clickBlock.x + "_" + this.clickBlock.y);
                null != e
                    ? (u.instance.PlaySound(u.instance.TB_sound.build_up),
                      r.instance.Fire(r.instance.MAP_UPBUILD, e.build, t),
                      this.clickBlock.blockC.BuildUp(this.clickBlock.x + "_" + this.clickBlock.y),
                      d.instance.AddEffect(d.instance.effectStr.buildDownEffect, e.build.x, e.build.y),
                      this._buildMenu.MenuHide())
                    : r.instance.Fire(r.instance.UIGM_TIPS, "该建筑已被摧毁!!!");
            }
        else e.gold1 < s[1] && e.gold2 < s[2] ? r.instance.Fire(r.instance.UIGM_TIPS, "金币、闪电不足,请升级床铺、闪电") : e.gold1 < s[1] ? r.instance.Fire(r.instance.UIGM_TIPS, "金币不足,请提升床铺") : r.instance.Fire(r.instance.UIGM_TIPS, "闪电不足,请提升游戏机");
    else {
        let t = s[5].split("_"),
            e = h.instance.build.GetBuildData(t[0], parseInt(t[1]));
            /* 升级前置条件 */
        r.instance.Fire(r.instance.UIGM_TIPS, "需要一个" + e[0]);
    }
}

可以看到判断了,将第7行的-=改成+=便可以实现金币不减反加

同样还有一处,道具是需要在场外购买的,这个在class n类修改

class M

应该是猛鬼的类,在这里看到了最大hp,当前hp,能量,速度;这里没需求改

class z

广告视频类

class Q extends J

含有猛鬼入场时间(30s),可更改

新手任务可直接完成

// 原代码
TaskPanel() {
    let t = h.instance.task.GetTaskText(this.taskIndex);
    t
        ? (this.taskIndex > h.instance.player.taskIndex && (h.instance.player.taskIndex++, (h.instance.player.gold += 5), (this.gold3.y = 225.5), p.instance.Gold3Effwct(this.gold3)),
          (this.taskText.text = t),
          (this.taskBtn.text = "未完成"),
          (this.taskBtn.color = "#675a59"),
          (this.taskBtn.underlineColor = "#675a59"),
          this.taskBtn.offAll())
        : (this.TaskOver(), this.tasklg.RemoveUpEvent());
}

// 修改后
TaskPanel() {
    let t = h.instance.task.GetTaskText(this.taskIndex);
    t
        ? (this.taskIndex > h.instance.player.taskIndex && (h.instance.player.taskIndex++, (h.instance.player.gold += 5), (this.gold3.y = 225.5), p.instance.Gold3Effwct(this.gold3)),
          (this.taskText.text = t),
          (this.taskBtn.text = "领取"), (this.taskBtn.color = "#23af00"), (this.taskBtn.underlineColor = "#23af00"), this.taskBtn.on(Laya.Event.CLICK, this, this.TaskBtnClickEvent))
        : (this.TaskOver(), this.tasklg.RemoveUpEvent());
}

也可以注释掉,但是第一次任务还是需要自己完成、

class tt

随机人机的姓名,没啥用

class et extends J

匹配时相关函数

有一个每秒可能匹配一个人忍不了,单机都是人机还匹配这么慢

// 原代码
MatchEvent() {
    if (this.headImg.length > 0) {
        this.time++, (this.pp.text = "匹配中  " + this.time + "s");
        let t = Math.random();
        if (t < 0.7) {
            t = Math.floor(Math.random() * this.headImg.length);
            let e = this.headImg[t],
                i = this.heads.getChildAt(e);
            this.headImg.splice(t, 1);
            let s = i.getChildByName("name"),
                _ = tt.instance.name;
            if (0 == e) (i.skin = "StartGameUI/mg_" + h.instance.player.trollIndex + ".png"), (h.instance.game.trollName = _);
            else {
                let t = Math.floor(Math.random() * this.playerSKin);
                (i.skin = "StartGameUI/player_" + t + ".png"), (h.instance.game.playerArr = { name: _, index: t });
            }
            (s.text = _), p.instance.Shake(i, 0.2), u.instance.PlaySound(u.instance.Other_sound.MP);
        }
    } else this._isMatch && (Laya.timer.clear(this, this.MatchEvent), this.StartGame(), (this.pp.visible = !1));
}

// 修改后
MatchEvent() {
    while (this.headImg.length > 0) {
        this.time++, (this.pp.text = "匹配中  " + this.time + "s");
        let t = Math.random();
        if (t < 0.7) {
            t = Math.floor(Math.random() * this.headImg.length);
            let e = this.headImg[t],
                i = this.heads.getChildAt(e);
            this.headImg.splice(t, 1);
            let s = i.getChildByName("name"),
                _ = tt.instance.name;
            if (0 == e) (i.skin = "StartGameUI/mg_" + h.instance.player.trollIndex + ".png"), (h.instance.game.trollName = _);
            else {
                let t = Math.floor(Math.random() * this.playerSKin);
                (i.skin = "StartGameUI/player_" + t + ".png"), (h.instance.game.playerArr = { name: _, index: t });
            }
            (s.text = _), p.instance.Shake(i, 0.2), u.instance.PlaySound(u.instance.Other_sound.MP);
        }
    }
    this._isMatch && (Laya.timer.clear(this, this.MatchEvent), this.StartGame(), (this.pp.visible = !1));
}

修改后的效果就是点击准备后秒进游戏了

class at extends J

可以发现调用了

ADVClickEvent() {
    Platform.video.playVideo({
        success: () => {
            u.instance.PlaySound(u.instance.Other_sound.tcOpen),
                this.TcEffectInit(),
                this.MoveDown(this.tc, this.advBtn.y, 1, 600, () => {
                    this.tc.play(0, !1, "open"), this.tc.on(Laya.Event.COMPLETE, this, this.open);
                }),
                (this.advBtn.visible = !1),
                (this.qq.visible = !1),
                this.MoveDown(this.closeBtn, this.closeBtn.y + this.closeBtn.height, 0, 200, () => {
                    this.closeBtn.visible = !1;
                });
        },
        fail: () => {
            r.instance.Fire(r.instance.UIGM_TIPS, "请观看完整视频,获得宝箱");
        },
    });
}

直接将success中的回调内容覆盖到该函数就好了。

搜索这个Platform.video.playVideo函数,发现有5次调用。以相同方式改掉(但是会报错,最终也没试)

class $ extends J

看视频领蜜罐币(player.gold)

输赢事件,即使输了,用赢方法覆盖输方法可以将输改为赢

class it extends J

有场外道具的购买代码

// 原代码
ShopBtnEvent(...t) {
    let e = t[0].split("_"),
        i = e[0],
        s = t[1],
        _ = h.instance.build.GetShopBuildMoney(i),
        n = _[1];
    h.instance.player.gold >= n
        ? ((h.instance.player.gold -= n), h.instance.player.ModifiedBuileprintQuantity(i, 1), (s.text = h.instance.player.GetBuileprintNum(i)), (this._gold.text = h.instance.player.gold.toString()), r.instance.Fire(r.instance.UIGM_TIPS, "购买成功"))
        : r.instance.Fire(r.instance.UIGM_TIPS, "钻石不足");
}

// 修改后(部分)
((h.instance.player.gold += n), h.instance.player.ModifiedBuileprintQuantity(i, 1), (s.text = h.instance.player.GetBuileprintNum(i)), (this._gold.text = h.instance.player.gold.toString()), r.instance.Fire(r.instance.UIGM_TIPS, "购买成功"));

改不改也没啥,毕竟我提取出来的安装包没有场外道具

class _t extends J

每次打开游戏有个公告,必须要强制看三秒,就在这里

this.gsTime = 3
// 改为1

去校验

刚开始修改完,打包安装发现报错,查了半天这个游戏使用的是layabox,然后有一个校验dcc的过程。

我不会去除校验过程(好像也不能去除),然后看了两篇资料https://ask.layabox.com/question/3678和https://ldc.layabox.com/doc/?nav=zh-as-7-2-1 ,决定重新生成文件内容的校验值,然后替换掉旧的

首先去除android.permission.INTERNET权限,这个软件还有乱七八糟的一堆权限,但是我没有去,删了会报错,我也懒得一个个验证,索性就只去除一个联网,防止热更新修改完的js文件

修改完文件后,将其复制到一个文件夹,npm安装好layadcc后运行命令

layadcc .

就会生成update文件夹,然后去把正确的校验值复制出来

先是修改filetable.txt和filetable1.txt里面文件名后的内容校验值;还有一个filetable.bin,使用010打开,然后查找int值,找到后将其修改

这样便完成了

总结

因为没去掉校验,修改比较麻烦,每次都得重新生成校验值填进去。最终修改的功能如下

  1. 修改金币闪电钻石不减反增

  2. 修改为秒匹配人机

  3. 修改场外道具定值10

  4. 删掉升级前置条件

  5. 删掉开局公告强制等待3秒

  6. 解锁全皮肤

  7. 新手任务可直接点完成

每次都是修改一个小功能填进去,修改校验值,如果报错还需重新改,上面记录的代码可能不是最终的,但都是这意思,关键点是对的。

其实能改的有很多,游戏地图都在这个文件里用数组存着,再加上没有混淆,甚至可以二次开发。

我这里仅仅是简单的分析了一下,这个文件有9000行,仅仅是一小部分,感兴趣的可以再深入分析。

最后,补张图

D69E11103F270435BC0B3F573FFAAEB8.jpg  TapTap猛鬼宿舍 抖音躺平发育 修改各种功能教程 第1张

忆笙

忆笙 主页 联系他吧

人间山河远阔,只想与你同行。

已有1位网友发表了看法:

欢迎 发表评论: