Skip to content

[Feature] Zone Scripting#4908

Merged
Kinglykrab merged 17 commits intomasterfrom
feature/zone_scripting
Jul 10, 2025
Merged

[Feature] Zone Scripting#4908
Kinglykrab merged 17 commits intomasterfrom
feature/zone_scripting

Conversation

@Kinglykrab
Copy link
Copy Markdown
Contributor

@Kinglykrab Kinglykrab commented Jun 1, 2025

Description

  • Adds support for attaching scripts to zones themselves.
  • Would eliminate the need for many controller NPCs and allow direct control of zone operations from the zone itself.

Type of change

  • New feature

Testing

Perl global_zone.pl

EVENT_CLICKDOOR

sub EVENT_CLICKDOOR {
	my $door_id = $door->GetDoorID();
	my $player_name = $player->GetCleanName();
	quest::debug("[EVENT_CLICKDOOR] door $door_id");
	quest::debug("[EVENT_CLICKDOOR] player $player_name");
}

image

EVENT_CLICK_OBJECT

sub EVENT_CLICK_OBJECT {
	my $object_name = $object->GetModelName();
	my $player_name = $player->GetCleanName();
	quest::debug("[EVENT_CLICK_OBJECT] objectid $objectid");
	quest::debug("[EVENT_CLICK_OBJECT] clicker_id $clicker_id");
	quest::debug("[EVENT_CLICK_OBJECT] object $object_name");
	quest::debug("[EVENT_CLICK_OBJECT] player $player_name");
}

image

EVENT_DEATH_ZONE

sub EVENT_DEATH_ZONE {
	my $killer_name = $killer->GetCleanName();
	quest::debug("[EVENT_DEATH_ZONE] killer_id $killer_id");
	quest::debug("[EVENT_DEATH_ZONE] killer_damage $killer_damage");
	quest::debug("[EVENT_DEATH_ZONE] killer_spell $killer_spell");
	quest::debug("[EVENT_DEATH_ZONE] killer_skill $killer_skill");
	quest::debug("[EVENT_DEATH_ZONE] killed_entity_id $killed_entity_id");
	quest::debug("[EVENT_DEATH_ZONE] combat_start_time $combat_start_time");
	quest::debug("[EVENT_DEATH_ZONE] combat_end_time $combat_end_time");
	quest::debug("[EVENT_DEATH_ZONE] damage_received $damage_received");
	quest::debug("[EVENT_DEATH_ZONE] healing_received $healing_received");
	quest::debug("[EVENT_DEATH_ZONE] killed_corpse_id $killed_corpse_id");
	quest::debug("[EVENT_DEATH_ZONE] killed_x $killed_x");
	quest::debug("[EVENT_DEATH_ZONE] killed_y $killed_y");
	quest::debug("[EVENT_DEATH_ZONE] killed_z $killed_z");
	quest::debug("[EVENT_DEATH_ZONE] killed_h $killed_h");
	quest::debug("[EVENT_DEATH_ZONE] killed_merc_id $killed_merc_id");
	quest::debug("[EVENT_DEATH_ZONE] killed_npc_id $killed_npc_id");
	quest::debug("[EVENT_DEATH_ZONE] killer $killer_name");
}

image

EVENT_DESPAWN_ZONE

sub EVENT_DESPAWN_ZONE {
	my $despawned_name = $despawned->GetCleanName();
	quest::debug("[EVENT_DESPAWN_ZONE] despawned_entity_id $despawned_entity_id");
	quest::debug("[EVENT_DESPAWN_ZONE] despawned_bot_id $despawned_bot_id");
	quest::debug("[EVENT_DESPAWN_ZONE] despawned_npc_id $despawned_npc_id");
	quest::debug("[EVENT_DESPAWN_ZONE] despawned $despawned_name");
}

image

EVENT_ENTERZONE

sub EVENT_ENTERZONE {
	my $player_name = $player->GetCleanName();
	quest::debug("[EVENT_ENTERZONE] player $player_name");
}

image

EVENT_LOOT_ZONE

sub EVENT_LOOT_ZONE {
	my $item_name = $item->GetName();
	my $corpse_name = $corpse->GetName();
	my $player_name = $player->GetCleanName();
	quest::debug("[EVENT_LOOT_ZONE] looted_id $looted_id");
	quest::debug("[EVENT_LOOT_ZONE] looted_charges $looted_charges");
	quest::debug("[EVENT_LOOT_ZONE] corpse_name $corpse_name");
	quest::debug("[EVENT_LOOT_ZONE] corpse_id $corpse_id");
	quest::debug("[EVENT_LOOT_ZONE] item $item_name");
	quest::debug("[EVENT_LOOT_ZONE] corpse $corpse_name");
	quest::debug("[EVENT_LOOT_ZONE] player $player_name");
}

image

EVENT_PAYLOAD

sub EVENT_PAYLOAD {
	quest::debug("[EVENT_PAYLOAD] payload_id $payload_id");
	quest::debug("[EVENT_PAYLOAD] payload_value $payload_value");
}

image

EVENT_PLAYER_PICKUP

sub EVENT_PLAYER_PICKUP {
	my $item_name = $item->GetName();
	my $player_name = $player->GetCleanName();
	quest::debug("[EVENT_PLAYER_PICKUP] picked_up_id $picked_up_id");
	quest::debug("[EVENT_PLAYER_PICKUP] picked_up_entity_id $picked_up_entity_id");
	quest::debug("[EVENT_PLAYER_PICKUP] item $item_name");
	quest::debug("[EVENT_PLAYER_PICKUP] player $player_name");
}

image

EVENT_POPUPRESPONSE

sub EVENT_POPUPRESPONSE {
	quest::debug("[EVENT_POPUPRESPONSE] popupid $popupid");
}

image

EVENT_SIGNAL

sub EVENT_SIGNAL {
	quest::debug("[EVENT_SIGNAL] $signal");
}

image

EVENT_SPAWN_ZONE

sub EVENT_SPAWN_ZONE {
	my $spawned_name = $spawned->GetCleanName();
	quest::debug("[EVENT_SPAWN_ZONE] spawned_entity_id $spawned_entity_id");
	quest::debug("[EVENT_SPAWN_ZONE] spawned_bot_id $spawned_bot_id");
	quest::debug("[EVENT_SPAWN_ZONE] spawned_npc_id $spawned_npc_id");
	quest::debug("[EVENT_SPAWN_ZONE] spawned $spawned_name");
}

image

EVENT_TIMER, EVENT_TIMER_PAUSE, EVENT_TIMER_RESUME, EVENT_TIMER_START, and EVENT_TIMER_STOP

sub EVENT_TIMER {
	quest::debug("[EVENT_TIMER] timer $timer");
	$zone->StopTimer($timer);
}

sub EVENT_TIMER_PAUSE {
	quest::debug("[EVENT_TIMER_PAUSE] timer $timer");
	quest::debug("[EVENT_TIMER_PAUSE] duration $duration");
}

sub EVENT_TIMER_RESUME {
	quest::debug("[EVENT_TIMER_RESUME] timer $timer");
	quest::debug("[EVENT_TIMER_RESUME] duration $duration");
}

sub EVENT_TIMER_START {
	quest::debug("[EVENT_TIMER_START] timer $timer");
	quest::debug("[EVENT_TIMER_START] duration $duration");
	$zone->PauseTimer($timer);
}

sub EVENT_TIMER_STOP {
	quest::debug("[EVENT_TIMER_STOP] timer $timer");
}

image

Lua global_zone.lua

EVENT_CLICK_DOOR

function event_click_door(e)
	eq.debug("[event_click_door] door " .. tostring(e.door:GetDoorID()))
	eq.debug("[event_click_door] client " .. e.other:GetCleanName())
end

image

EVENT_CLICK_OBJECT

function event_click_object(e)
	eq.debug("[event_click_object] object " .. tostring(e.object:GetID()))
	eq.debug("[event_click_object] client " .. e.other:GetCleanName())
end

image

EVENT_DEATH_ZONE

function event_death_zone(e)
	eq.debug("[event_death_zone] other " .. e.other:GetCleanName())
	eq.debug("[event_death_zone] killer_id " .. e.killer_id)
	eq.debug("[event_death_zone] damage " .. e.damage)
	if e.spell.valid then
		eq.debug("[event_death_zone] spell " .. e.spell:GetID())
	else
		eq.debug("[event_death_zone] spell none")
	end
	eq.debug("[event_death_zone] skill_id " .. e.skill_id)
	eq.debug("[event_death_zone] killed_entity_id " .. e.killed_entity_id)
	eq.debug("[event_death_zone] combat_start_time " .. e.combat_start_time)
	eq.debug("[event_death_zone] combat_end_time " .. e.combat_end_time)
	eq.debug("[event_death_zone] damage_received " .. e.damage_received)
	eq.debug("[event_death_zone] healing_received " .. e.healing_received)
	eq.debug("[event_death_zone] corpse " .. e.corpse:GetName())
	eq.debug("[event_death_zone] killed " .. e.killed:GetCleanName())
end

image

EVENT_DESPAWN_ZONE

function event_despawn_zone(e)
	eq.debug("[event_despawn_zone] other " .. e.other:GetCleanName())
end

image

EVENT_ENTER_ZONE

function event_enter_zone(e)
	eq.debug("[event_enter_zone] client " .. e.other:GetCleanName())
end

image

EVENT_LOOT_ZONE

function event_loot_zone(e)
	eq.debug("[event_loot_zone] other " .. e.other:GetCleanName())
	eq.debug("[event_loot_zone] item " .. e.item:GetName())
	eq.debug("[event_loot_zone] corpse " .. e.corpse:GetCleanName())
end

image

EVENT_PAYLOAD

function event_payload(e)
	eq.debug("[event_payload] payload_id " .. tostring(e.payload_id));
	eq.debug("[event_payload] payload_value " .. e.payload_value);
end

image

EVENT_PLAYER_PICKUP

function event_player_pickup(e)
	eq.debug("[event_player_pickup] other " .. e.other:GetCleanName())
	eq.debug("[event_player_pickup] item " .. e.item:GetName())
end

image

EVENT_POPUP_RESPONSE

function event_popup_response(e)
	eq.debug("[event_popup_response] client " .. e.other:GetCleanName())
	eq.debug("[event_popup_response] popup_id " .. tostring(e.popup_id))
end

image

EVENT_SIGNAL

function event_signal(e)
	eq.debug("[event_signal] signal " .. tostring(e.signal));
end

image

EVENT_SPAWN_ZONE

function event_spawn_zone(e)
	eq.debug("[event_spawn_zone] other " .. e.other:GetCleanName())
end

image

EVENT_TIMER, EVENT_TIMER_START, and EVENT_TIMER_STOP

function event_timer(e)
	eq.debug("[event_timer] timer " .. e.timer);
	eq.world_wide_message(335, "Timer fired!");
	eq.get_zone():StopTimer(e.timer)
end

function event_timer_start(e)
	eq.world_wide_message(335, "Timer started!")
	eq.debug("[event_timer_start] timer " .. e.timer);
	eq.debug("[event_timer_start] duration " .. tostring(e.duration));
end

function event_timer_stop(e)
	eq.debug("[event_timer_stop] timer " .. e.timer);
end

image

EVENT_TIMER_PAUSE

function event_timer_start(e)
	eq.world_wide_message(335, "Timer started!")
	eq.debug("[event_timer_start] timer " .. e.timer);
	eq.debug("[event_timer_start] duration " .. tostring(e.duration));
	eq.get_zone():PauseTimer(e.timer)
end

function event_timer_pause(e)
	eq.debug("[event_timer_pause] timer " .. e.timer);
	eq.debug("[event_timer_pause] duration " .. tostring(e.duration));
end

image

EVENT_TIMER_RESUME

function event_timer_pause(e)
	eq.debug("[event_timer_pause] timer " .. e.timer)
end

function event_timer_resume(e)
	eq.debug("[event_timer_resume] timer " .. e.timer)
	eq.debug("[event_timer_resume] duration " .. tostring(e.duration))
end

function event_timer_start(e)
	eq.debug("[event_timer_start] timer " .. e.timer)
	eq.get_zone():PauseTimer(e.timer)
end

image

Checklist

  • I have tested my changes
  • I have performed a self-review of my code. Ensuring variables, functions and methods are named in a human-readable way, comments are added only where naming of variables, functions and methods can't give enough context.
  • I own the changes of my code and take responsibility for the potential issues that occur

@MortimerGreenwald
Copy link
Copy Markdown
Contributor

you have my attention.....

@Valorith
Copy link
Copy Markdown
Contributor

Valorith commented Jun 3, 2025

This one sounds very interesting indeed! :D

@Akkadius Akkadius marked this pull request as draft June 9, 2025 17:44
@Akkadius
Copy link
Copy Markdown
Contributor

Akkadius commented Jun 9, 2025

Per DM's with @Kinglykrab moving this to draft until it is more in a ready state

@catapultam-habeo
Copy link
Copy Markdown
Contributor

This one is exciting

@Kinglykrab Kinglykrab marked this pull request as ready for review June 19, 2025 13:31
@Kinglykrab Kinglykrab changed the title [WIP] Zone Scripting [Feature] Zone Scripting Jun 19, 2025
Copy link
Copy Markdown
Member

@KimLS KimLS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall I don't see much wrong with this.

I'm not sure the changes to StartQuest stylistically are much better/worse than what we were doing. I'm not willing to hold it up over that but there's a few changes I'd like made tangentially to that.

@Kinglykrab
Copy link
Copy Markdown
Contributor Author

Overall I don't see much wrong with this.

I'm not sure the changes to StartQuest stylistically are much better/worse than what we were doing. I'm not willing to hold it up over that but there's a few changes I'd like made tangentially to that.

This was a change similar to the other change where we had 10+ parameters in multiple methods unnecessarily. I'll probably do some future cleanup, but for the time being, I only changed what I felt was necessary to not cause even more parameter bloat.

@KimLS
Copy link
Copy Markdown
Member

KimLS commented Jun 23, 2025

Build is still broken on the following line:

C:\Windows\Temp\drone-0ARp7XqOvGA3Ue1H\drone\src\zone\quest_parser_collection.cpp(1573,8): error C2039: 'GetQuestsPath': is not a member of 'PathManager'

Linux reports a similar error more verbosely so I included the windows one.

@Kinglykrab Kinglykrab force-pushed the feature/zone_scripting branch from 8408615 to 9a75d34 Compare July 1, 2025 22:31
@nytmyr
Copy link
Copy Markdown
Contributor

nytmyr commented Jul 2, 2025

Can properly execute the zone level scripts for global and per zone as well as versioning, but it seems to supersede all other scripts at the zone level. Individual scripts don't seem to fire (hails, hand-ins). Was testing with the stock Elementalist_Somat.pl for PoK.

Edit:
Discussed with KK but just for notation:
NPC scripts for Perl are not firing with or without zone level scripts.

player.pl, bot.pl, zone.pl, global_zone.pl work.

Anything NPC related does not - default.pl, <npc_id/name>.pl, global_npc.pl

All Lua types work.

@Kinglykrab
Copy link
Copy Markdown
Contributor Author

NPCs are now functional.
image

@Kinglykrab Kinglykrab merged commit 323a0c0 into master Jul 10, 2025
2 checks passed
@Kinglykrab Kinglykrab deleted the feature/zone_scripting branch July 10, 2025 19:08
@Akkadius Akkadius mentioned this pull request Aug 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants