• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

AAC [Znote AAC] Deathlist

ralke

(҂ ͠❛ ෴ ͡❛)ᕤ
Joined
Dec 17, 2011
Messages
1,557
Solutions
28
Reaction score
881
Location
Santiago - Chile
GitHub
ralke23
Twitch
ralke23
Using OTX 2 (0.3.7)
Old threads with the same topic:
Death list | OTLand
AAC - Znote death list | OTLand

Hi! I wanted to ask something about Znote AAC this time. When a character gets killed by multiple targets, the deathlist of characterprofile.php is only showing one of the killers. For example, if you were killed by a minotaur, player (a) and player (b) , the deathlist will only show:

- Killed at level 30 by a minotaur ...... or ...... Killed at level 30 by Player (a)
But I want to show the whole list.
- Killed at level 30 by Player (a), Player (b) and a minotaur

Here is how the deathlist is written for 0.3.7
PHP:
                } elseif (in_array($config['ServerEngine'], array('TFS_03', 'OTHIRE'))) {
                    //mysql_select_single("SELECT * FROM players WHERE name='TEST DEBUG';");
                    $array = user_fetch_deathlist03($user_id);
                    if ($array) {
                        // Design and present the list
                        foreach ($array as $value):
                            $value[3] = user_get_killer_id(user_get_kid($value['id']));
                            if ($value[3] !== false && $value[3] >= 1) {
                                $namedata = user_character_data((int)$value[3], 'name');
                                if ($namedata !== false) {
                                    $value[3] = $namedata['name'];
                                    $value[3] = 'player: <a href="characterprofile.php?name='. $value[3] .'">'. $value[3] .'</a>';
                                } else {
                                    $value[3] = 'deleted player.';
                                }
                            } else {
                                $value[3] = user_get_killer_m_name(user_get_kid($value['id']));
                                if ($value[3] === false) {
                                    $value[3] = 'deleted player.';
                                }
                            }
                            ?>
                            <tr>
                                <td><?php echo getClock($value['date'], true, true); ?></td>
                                <td><?php echo 'Killed at level '. $value['level'] .' by '. $value[3]; ?></td>
                            </tr>
                        <?php endforeach;
                    } else {
                        ?>
                        <tr>
                            <td colspan="2">This player has never died.</td>
                        </tr>
                        <?php
                    }
                }
                ?>

And here are all versions together (TFS_03, TFS_10, TFS_02):

PHP:
    <!-- DEATH LIST -->
        <table class="deathlist">
            <thead>
                <tr class="yellow">
                    <th colspan="2">Death List</th>
                </tr>
            </thead>
            <tbody>
                <?php
                if ($config['ServerEngine'] == 'TFS_10') {
                    $deaths = mysql_select_multi("
                        SELECT
                            `player_id`,
                            `time`,
                            `level`,
                            `killed_by`,
                            `is_player`,
                            `mostdamage_by`,
                            `mostdamage_is_player`,
                            `unjustified`,
                            `mostdamage_unjustified`
                        FROM `player_deaths`
                        WHERE `player_id`=$user_id
                        ORDER BY `time` DESC
                        LIMIT 10;
                    ");

                    if ($deaths) {
                        foreach ($deaths as $d) {
                            $lasthit = ($d['is_player'])
                            ? "<a href='characterprofile.php?name=".$d['killed_by']."'>".$d['killed_by']."</a>"
                            : $d['killed_by'];

                            ?>
                            <tr>
                                <td><?php echo getClock($d['time'], true, true); ?></td>
                                <td>
                                    <?php
                                    echo "Killed at level ".$d['level']." by {$lasthit}";
                                    if ($d['unjustified']) {
                                        echo " <font color='red' style='font-style: italic;'>(unjustified)</font>";
                                    }
                                    $mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : false;
                                    if ($mostdmg) {
                                        $mostdmg = ($d['mostdamage_is_player'])
                                        ? "<a href='characterprofile.php?name=".$d['mostdamage_by']."'>".$d['mostdamage_by']."</a>"
                                        : $d['mostdamage_by'];

                                        echo "<br>and by $mostdmg.";

                                        if ($d['mostdamage_unjustified']) {
                                            echo " <font color='red' style='font-style: italic;'>(unjustified)</font>";
                                        }
                                    } else {
                                        echo " <b>(soloed)</b>";
                                    }
                                    ?>
                                </td>
                            </tr>
                            <?php
                        }
                    } else {
                        ?>
                        <tr>
                            <td colspan="2">This player has never died.</td>
                        </tr>
                        <?php
                    }
                } elseif ($config['ServerEngine'] == 'TFS_02') {
                    $array = user_fetch_deathlist($user_id);
                    if ($array) {
                        foreach ($array as $value):
                            if ($value['is_player'] == 1) {
                                $value['killed_by'] = 'player: <a href="characterprofile.php?name='. $value['killed_by'] .'">'. $value['killed_by'] .'</a>';
                            } else {
                                $value['killed_by'] = 'monster: '. $value['killed_by'] .'.';
                            }
                            ?>
                            <tr>
                                <td><?php echo getClock($value['time'], true, true); ?></td>
                                <td><?php echo 'Killed at level '. $value['level'] .' by '. $value['killed_by']; ?></td>
                            </tr>
                        <?php endforeach;
                    } else {
                        ?>
                        <tr>
                            <td colspan="2">This player has never died.</td>
                        </tr>
                        <?php
                    }
                } elseif (in_array($config['ServerEngine'], array('TFS_03', 'OTHIRE'))) {
                    //mysql_select_single("SELECT * FROM players WHERE name='TEST DEBUG';");
                    $array = user_fetch_deathlist03($user_id);
                    if ($array) {
                        // Design and present the list
                        foreach ($array as $value):
                            $value[3] = user_get_killer_id(user_get_kid($value['id']));
                            if ($value[3] !== false && $value[3] >= 1) {
                                $namedata = user_character_data((int)$value[3], 'name');
                                if ($namedata !== false) {
                                    $value[3] = $namedata['name'];
                                    $value[3] = 'player: <a href="characterprofile.php?name='. $value[3] .'">'. $value[3] .'</a>';
                                } else {
                                    $value[3] = 'deleted player.';
                                }
                            } else {
                                $value[3] = user_get_killer_m_name(user_get_kid($value['id']));
                                if ($value[3] === false) {
                                    $value[3] = 'deleted player.';
                                }
                            }
                            ?>
                            <tr>
                                <td><?php echo getClock($value['date'], true, true); ?></td>
                                <td><?php echo 'Killed at level '. $value['level'] .' by '. $value[3]; ?></td>
                            </tr>
                        <?php endforeach;
                    } else {
                        ?>
                        <tr>
                            <td colspan="2">This player has never died.</td>
                        </tr>
                        <?php
                    }
                }
                ?>
            </tbody>
        </table>

As I see the TFS_10 has this feature, expressed by new tables such as mostdamage_by, mostdamage_is_player... among others.

PHP:
   $deaths = mysql_select_multi("
                        SELECT
                            `player_id`,
                            `time`,
                            `level`,
                            `killed_by`,
                            `is_player`,
                            `mostdamage_by`,
                            `mostdamage_is_player`,
                            `unjustified`,
                            `mostdamage_unjustified`
                        FROM `player_deaths`
                        WHERE `player_id`=$user_id
                        ORDER BY `time` DESC
                        LIMIT 10;
                    ");

I wonder if using the TFS_10 code as TFS_03 and adding those new tables will make the deathlist work as intended?. Before testing this I would like to ask... You guys know better than me if those tables are going to work on OTX 2 (0.3.7) or if there's another way to change the deathlist method.

Also got the config.lua configured this way:

Lua:
    -- deathAssistCount to 1
    -- useFairfightReduction to false
    -- fairFightTimeRange = 30
    deathListEnabled = true
    deathListRequiredTime = 1 * 60 * 1000
    maxDeathRecords = 5

This is telling me that a deathAssist function and the maxDeathRecords are part of the sources of OTX 2 and theres a way to fit it with the deathlist.
Hope I explained well, i'm looking for help to make this work :D

Regards,
ralke
 
Last edited:
OTX2 schema structure does not seem to perfectly match the TFS_03 or TFS_10 compatibility configuration on Znote AAC, so we might need to rewrite this part to accomodate assist kills.

Looking at the OTX2 schema, there are multiple tables involved:
SQL:
-- Stores death rows for a player_id, each death row has its unique death_id, 
-- date when death happened and level the player was
CREATE TABLE `player_deaths`
(
	`id` INT NOT NULL AUTO_INCREMENT, --> Also known as: death_id in other reference tables
	`player_id` INT NOT NULL,
	`date` BIGINT UNSIGNED NOT NULL,
	`level` INT UNSIGNED NOT NULL,
	PRIMARY KEY (`id`), INDEX (`date`),
	FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB;

-- When someone dies, something else kills. This lists all "kill_id" for a death_id
-- And lets us know if this row is the final hit and/or unjustified
-- One death id can have multiple kill_id,
-- we don't know if kill_id represent a player or environment (monster, map objects like trap and elemental fields)
CREATE TABLE `killers`
(
	`id` INT NOT NULL AUTO_INCREMENT, --> Also known as: kill_id in other reference tables
	`death_id` INT NOT NULL,
	`final_hit` TINYINT(1) UNSIGNED NOT NULL DEFAULT FALSE,
	`unjustified` TINYINT(1) UNSIGNED NOT NULL DEFAULT FALSE,
	PRIMARY KEY (`id`),
	FOREIGN KEY (`death_id`) REFERENCES `player_deaths`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB;

-- This table determines if a kill_id (from `killers` table) is connected to a player, and let us know the player_id
CREATE TABLE `player_killers`
(
	`kill_id` INT NOT NULL,
	`player_id` INT NOT NULL,
	FOREIGN KEY (`kill_id`) REFERENCES `killers`(`id`) ON DELETE CASCADE,
	FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB;

-- This table determines if a kill_id (from `killers` table) is connected to environment/monster, and let us know the name
CREATE TABLE `environment_killers`
(
	`kill_id` INT NOT NULL,
	`name` VARCHAR(255) NOT NULL,
	FOREIGN KEY (`kill_id`) REFERENCES `killers`(`id`) ON DELETE CASCADE
) ENGINE = InnoDB;

I can probably write this query, but I want access to a demo database where these tables are populated with data so I can test this out as I code. I don't feel comfortable tackling this challenge blind. :p
 
Hi @Znote thanks for reply! I already moved on to 1.3, but has the old database backup in my PC. Haven't used this tables much, but has the needed information on player_deaths and come from 0.3.7 schemas. Couldn't clone the znote tables so I modified it a little and send it exactly how it was used.
 

Attachments

  • ral1995-db_2021-05-05.sql
    177.3 KB · Views: 8 · VirusTotal
Such an old thread. Sorry for bumping this. I think this will solve:
PHP:
$mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : false;

Change false to true
PHP:
$mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : true;

Regards :)
 
Such an old thread. Sorry for bumping this. I think this will solve:
PHP:
$mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : false;

Change false to true
PHP:
$mostdmg = ($d['mostdamage_by'] !== $d['killed_by']) ? true : true;

Regards :)
Found another bug at this. When you get killed, and you active 'mostdamage_by' and 'killed by' (on the script), if the most damage was done by the same creature that killed you, it will tell two times the same creature. For example, if I died by a demon and a fire elemental, the most damage by should be the fire elemental, and killed by demon, supposing that it did the most damage. But if you see the character's dead log it shows killed by "Demon" and a "Demon". If someone can help me fixing this will be appreciated.

So here we go. The table structure is player_id, time, level, killed by, is_player, mostdamage_by, mostdamage_is_player, unjustified, and mostdamage_unjustified.

What I think that could be the best solution is to generate if statements, in a way that if the player was killed by mostdamage_by then use mostdamage2_by. Thinking like this, I guess that tables should hold at least five most damages rows, for each table (mostdamage_by, mostdamage_is_player, mostdamage_unjustified).

I'm not sure if saving that much data will be something to care about. But thinking on all this, there so many lines involved on this. What is the best thing to do? The most part that is involved here is at playerdeath.lua, if at least I can fix the first thing I said about duplicating the creature that killed you would be enought! Thanks in advance.

My playerdeath.lua:
Lua:
local deathListEnabled = true
local maxDeathRecords = 15

local function sendWarStatus(guildId, enemyGuildId, warId, playerName, killerName)
    local guild, enemyGuild = Guild(guildId), Guild(enemyGuildId)
    if not guild or not enemyGuild then
        return
    end

    local resultId = db.storeQuery("SELECT `guild_wars`.`id`, (SELECT `limit` FROM `znote_guild_wars` WHERE `znote_guild_wars`.`id` = `guild_wars`.`id`) AS `limit`, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild1`) guild1_kills, (SELECT COUNT(1) FROM `guildwar_kills` WHERE `guildwar_kills`.`warid` = `guild_wars`.`id` AND `guildwar_kills`.`killerguild` = `guild_wars`.`guild2`) guild2_kills FROM `guild_wars` WHERE (`guild1` = " .. guildId .. " OR `guild2` = " .. guildId .. ") AND `status` = 1 AND `id` = " .. warId)
    if resultId then

        local guild1_kills = result.getNumber(resultId, "guild1_kills")
        local guild2_kills = result.getNumber(resultId, "guild2_kills")
        local limit = result.getNumber(resultId, "limit")
        result.free(resultId)

        local members = guild:getMembersOnline()
        for i = 1, #members do
            members[i]:sendChannelMessage("", string.format("%s fue asesinado por %s. El nuevo marcador es %d:%d eliminaciones (limite: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
        end

        local enemyMembers = enemyGuild:getMembersOnline()
        for i = 1, #enemyMembers do
            enemyMembers[i]:sendChannelMessage("", string.format("%s fue asesinado por %s. El nuevo marcador es %d:%d eliminaciones (limit: %d)", playerName, killerName, guild1_kills, guild2_kills, limit), TALKTYPE_CHANNEL_R1, CHANNEL_GUILD)
        end

        if guild1_kills >= limit or guild2_kills >= limit then
            db.query("UPDATE `guild_wars` SET `status` = 4, `ended` = " .. os.time() .. " WHERE `status` = 1 AND `id` = " .. warId)
            Game.broadcastMessage(string.format("%s acaba de ganar la guerra contra %s.", guild:getName(), enemyGuild:getName()), MESSAGE_EVENT_ADVANCE)
        end
    end
end

function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
    local playerId = player:getId()
    if nextUseStaminaTime[playerId] then
        nextUseStaminaTime[playerId] = nil
    end
    player:sendTextMessage(MESSAGE_EVENT_ADVANCE, "Has muerto.")
    if not deathListEnabled then
        return
    end

    local byPlayer = 0
    local killerName
    if killer then
        if killer:isPlayer() then
            byPlayer = 1
        else
            local master = killer:getMaster()
            if master and master ~= killer and master:isPlayer() then
                killer = master
                byPlayer = 1
            end
        end
        killerName = killer:getName()
    else
        killerName = "elemento de campo"
    end

    local byPlayerMostDamage = 0
    local mostDamageKillerName
    if mostDamageKiller then
        if mostDamageKiller:isPlayer() then
            byPlayerMostDamage = 1
        else
            local master = mostDamageKiller:getMaster()
            if master and master ~= mostDamageKiller and master:isPlayer() then
                mostDamageKiller = master
                byPlayerMostDamage = 1
            end
        end
        mostDamageName = mostDamageKiller:getName()
    else
        mostDamageName = "elemento de campo"
    end

    local playerGuid = player:getGuid()
    db.query("INSERT INTO `player_deaths` (`player_id`, `time`, `level`, `killed_by`, `is_player`, `mostdamage_by`, `mostdamage_is_player`, `unjustified`, `mostdamage_unjustified`) VALUES (" .. playerGuid .. ", " .. os.time() .. ", " .. player:getLevel() .. ", " .. db.escapeString(killerName) .. ", " .. byPlayer .. ", " .. db.escapeString(mostDamageName) .. ", " .. byPlayerMostDamage .. ", " .. (lastHitUnjustified and 1 or 0) .. ", " .. (mostDamageUnjustified and 1 or 0) .. ")")
    local resultId = db.storeQuery("SELECT `player_id` FROM `player_deaths` WHERE `player_id` = " .. playerGuid)

    local deathRecords = 0
    local tmpResultId = resultId
    while tmpResultId ~= false do
        tmpResultId = result.next(resultId)
        deathRecords = deathRecords + 1
    end

    if resultId ~= false then
        result.free(resultId)
    end

    local limit = deathRecords - maxDeathRecords
    if limit > 0 then
        db.asyncQuery("DELETE FROM `player_deaths` WHERE `player_id` = " .. playerGuid .. " ORDER BY `time` LIMIT " .. limit)
    end

    if byPlayer == 1 then
        local targetGuild = player:getGuild()
        targetGuild = targetGuild and targetGuild:getId() or 0
        if targetGuild ~= 0 then
            local killerGuild = killer:getGuild()
            killerGuild = killerGuild and killerGuild:getId() or 0
            if killerGuild ~= 0 and targetGuild ~= killerGuild and isInWar(playerId, killer:getId()) then
                local warId = false
                resultId = db.storeQuery("SELECT `id` FROM `guild_wars` WHERE `status` = 1 AND ((`guild1` = " .. killerGuild .. " AND `guild2` = " .. targetGuild .. ") OR (`guild1` = " .. targetGuild .. " AND `guild2` = " .. killerGuild .. "))")
                if resultId ~= false then
                    warId = result.getNumber(resultId, "id")
                    result.free(resultId)
                end

                if warId ~= false then
                    local playerName = player:getName()
                    db.asyncQuery("INSERT INTO `guildwar_kills` (`killer`, `target`, `killerguild`, `targetguild`, `time`, `warid`) VALUES (" .. db.escapeString(killerName) .. ", " .. db.escapeString(playerName) .. ", " .. killerGuild .. ", " .. targetGuild .. ", " .. os.time() .. ", " .. warId .. ")")
                    addEvent(sendWarStatus, 1000, killerGuild, targetGuild, warId, playerName, killerName)
                end
            end
        end
    end
end

Regards!
 
Back
Top