Jump to content
Naruto607

NooseMod: having trouble with main callout

Recommended Posts

Actually, I don't know if I'm correct to post my problem right here, but I do have a problem.

I'm designing a new LCPDFR API plugin that brings Counter-Strike-styled game into GTA, but I encountered a problem.

Long story short, I designed this based on the old NooseMod script that released since 2009 and I wanted to enhance it, using LCPDFR engine.

I wanted to contact the author of the mod, but for the past 8 years he was never resurfaced, nor speaking online. Also the site I wanted to get in contact with was closed.

And yeah, I do have adequate skills in GTA scripting after learning from C# tutorial book and the internet.

 

My script comprises of many classes; very complicated. I redesigned it based from the original NooseMod. Terrorist Pursuit callout works without any issues except, when it comes to the main callout (NooseMod). I made 3 attempts on forcing the callout after changing model to SWAT member, but it always caused the game to crash. LCPDFR.log records NO exceptions, but the Scripthookdotnet.log records it, which is unique IMO.

 

I have attached 3 logs (or full preview from my blog post: "Well, at least I tried..."). Any help will be appreciated.

 

P.S.: If anyone wants to test my source code for debugging, I published my codes as a repository on my GitHub here: https://github.com/Naruto607/NooseMod

It's my third debug since the initial commit on 30/7.

ScriptHookDotNet.log

AdvancedHook.log

LCPDFR.log


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

Share this post


Link to post
Share on other sites
14 hours ago, LtFlash said:

I feel like 2 factors are important here:

1) SoundPlayer/Audio used in NooseMod,

2) .NET version target set in properties of your project.

Try to temporarily comment out audio class and check if it works.

https://stackoverflow.com/questions/4018924/mixed-mode-assembly-is-built-against-version-v1-1-4322

https://stackoverflow.com/questions/3179028/mixed-mode-assembly-in-net-4

https://stackoverflow.com/questions/6425707/mixed-mode-assembly-is-built-against-version-v2-0-50727-of-the-runtime

I'll give it a shot. Thanks @LtFlash.

 

Edit: Looks good, no game crashes, but apparently I'm running on something I want to figure out on my own, but... oh well...

Looks like I'm getting into the programming world...

 

I've been running a recently test on missions but I got stuck on "ArgumentOutOfRange" exception. On my other tests using Listing in Console Application is fine (I did an approx. 2 times with changing codes and adding StreamReader into it), but not with the NooseMod, even though the list was within the range (0 to 7 - there are 8 missions provided from the original NooseMod script). I'm trying to chase this issue to find out what caused the trouble, but if anyone got time to spare thoughts, I'd be happy to oblige.

LCPDFR.log

 

Edit2: Actually, I got that problem sorted out.

Edited by Naruto607
Problem solved

“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

Hey,

actually while I was developing, I got a question.

 

In details, there's this unique LCPDFR feature about "search radius" for knowing last location of suspect when the pursuing police/law enforcer has lost contact, like the ones in original GTA when a player is being chased by a police. Can't tell by screenshots because I'm still developing but I remember about "visual on suspect lost" or something. When the suspect has escaped the police (definitely after escaping the search radius for a period of time), I'd like to add an option to clear the mission peds list in my NooseMod project, that is, specific for that suspect that escaped.

 

Will this part of coding work? I'm still curious, though, because I did beta tests alone.

        private void GetArrestedTerrorists()
        {
            if (isPursuitSessionActive && missionPeds.Count != 0)
            {
                foreach (LPed myped in missionPeds)
                {
                    if (myped.IsAlive && myped.HasBeenArrested && myped.Exists())
                    {
                        missionPeds.Remove(myped);
                        arrestedSuspects.Add(myped);
                    }
                    // whether IsDead return true and HasBeenArrested return false
                    else if (myped.IsDead && !myped.HasBeenArrested && myped.Exists())
                    { missionPeds.Remove(myped); deadSuspects.Add(myped); }
                    // If the suspect has lost visual and escaped
                    else if (!myped.Exists()) missionPeds.Remove(myped);
                }
            }
        }

I'm focusing to the one that commented "If the suspect has lost visual and escaped". Wonder if that won't work.


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

If you want to check if a pursuit was terminated because of the suspect has escaped a better way is to check

Functions.IsPursuitStillRunning(pursuitHandle);

I don't know any method of checking if NPC has "visual" on the suspect, maybe except of checking the blip of the suspect but that might be faulty.

Another thing I'd change is to place an existence check as the 1st expression of the loop, like that:

foreach (LPed myped in missionPeds)
{
	if(myped == null || !myped.Exists())
	{
		missionPeds.Remove(myped);
		continue;
	}

	//your code w/o Exists() checks
}

I'd do so because IV removes peds often and performing anything on a non-existent ped will cause an exception.

Share this post


Link to post
Share on other sites
8 hours ago, LtFlash said:

If you want to check if a pursuit was terminated because of the suspect has escaped a better way is to check


Functions.IsPursuitStillRunning(pursuitHandle);

I don't know any method of checking if NPC has "visual" on the suspect, maybe except of checking the blip of the suspect but that might be faulty.

Another thing I'd change is to place an existence check as the 1st expression of the loop, like that:


foreach (LPed myped in missionPeds)
{
	if(myped == null || !myped.Exists())
	{
		missionPeds.Remove(myped);
		continue;
	}

	//your code w/o Exists() checks
}

I'd do so because IV removes peds often and performing anything on a non-existent ped will cause an exception.

I'll take your advice, @LtFlash.

 

Well, you know more of LCPDFR API programming than mine. I had to do major edits on the code because when using "while" and "do... while" loop, the game hangs instead of processing information. Also the "RegisterStateCallback" method seems to get the callout looks awkward (you responded the callout and suddenly you are already in position while you don't) - I only use it on my SecuricarThefts plugin for LCPDFR, the one with the Shooting callout with Securicar personnel involvement. And I've been putting tutorial inside it but so far not yet tested because I need to rest. Well, I'm sure it works, because I can predict what will happen next.

 

Anyway I'm still debugging the plugin without Audio Player for a while until it works and meets my minimal demands of a working plugin. Still...

 

There's these functions I've been implementing from the original NooseMod, but current version of SHDN deprecate the functions (or those are obsolete). I actually don't know how to use "dynamic" method, because I currently know the basics, but not with handling the so-called "metadata". I haven't yet tested this, because the callout runs on Difficulty and Hardcore Mode check.


                        // Standard ped do not have option to grab a Blip instance, used Metadata instead
                        // Method is similar to the old NooseMod, but not for suspects
                        // TODO: Look for other alternative (to bypass deprecated method)
                        myped.SetMetadata<Blip>("blip", true, hostageBlip);


                    Blip metadata = myped.GetMetadata<Blip>("blip");
                    if (metadata != null) metadata.Delete();

I believe these are used in old SHDN, but I can't exactly confirm the version, could be older than the one distributed alongside the LCPDFR. Could that cause the side-effect in LCPDFR and regular script (which also use that method)? If so, how to replace it (using Metadata then followed by a dynamic function)?

 

I bet no one has ever done this than me, except in the old times where the original author designed the NooseMod (that eventually designed for the older version of GTA IV with older SHDN). None in any tutorials explain about it (especially for JulioNIB's).

 

Likewise, I'm still developing, but needed rest a bit often.


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

1) To be able to use (potentially) infinite loops w/o freezing you have to yield after each pass, you can use Wait(0):

while (true)
{
  //your code
  Game.WaitInCurrentScript(0);
}

2) RegisterStateCallback: you might be interested in my and LMS' previous post about this mechanism: 

 it works completely fine when used properly.

3) You can get ped's blip this way:

//LCPD:FR LPed:
LPed p;
Blip pedBlip = p.Blip;

//SHDN Ped:
Blip[] blips = Blip.GetAllBlipsOfType(BlipType.Ped);
Blip b = blips.Find(b => b.GetAttachedItem() == yourSuspect);

4) You should open SDHN and LCPD:FR in VS Object Browser and familiarize yourself with members of classes that form those libraries. It'll make developing easier as you'll know what you can do.

Share this post


Link to post
Share on other sites
2 hours ago, LtFlash said:

1) To be able to use (potentially) infinite loops w/o freezing you have to yield after each pass, you can use Wait(0):


while (true)
{
  //your code
  Game.WaitInCurrentScript(0);
}

2) RegisterStateCallback: you might be interested in my and LMS' previous post about this mechanism: 

 it works completely fine when used properly.

3) You can get ped's blip this way:


//LCPD:FR LPed:
LPed p;
Blip pedBlip = p.Blip;

//SHDN Ped:
Blip[] blips = Blip.GetAllBlipsOfType(BlipType.Ped);
Blip b = blips.Find(b => b.GetAttachedItem() == yourSuspect);

4) You should open SDHN and LCPD:FR in VS Object Browser and familiarize yourself with members of classes that form those libraries. It'll make developing easier as you'll know what you can do.

Well... I dunno what to say, but I appreciate your feedback.

 

However, I know from the way you said about "RegisterStateCallback" (I even declare it in MissionState class), but mine's very different. Like I said, the callout looks awkward no matter I force setting the State to what I want, although I did follow what you said before you tell me that. I currently had to remove the RegisterStateCallback function and process every method in Process area. That, fortunately, sorted (solved) the problem out.

 

BTW, should I change 2^n (2 powered by n number) with the regular integer (0, 1, 2, 4, 8, 16, and so on), or keep it as is? 2^1 is similar to 2.

        public override void Process()
        {
            base.Process();

          // here is where I bypass the awkward callout when RegisterStateCallback is used
          // It's stable, perhaps
            if (mission == MissionState.GoingToMissionLocation)
            {
                WaitingForPlayer(); return;
            }

            if (mission == MissionState.WaitForTeamInsertion)
            {
                DispatchTeam(); return;
            }

            if (mission == MissionState.Initialize)
            {
                InitiateShootout(); return;
            }

            if (mission == MissionState.DuringMission) TrackPedsInPlayerRoom();

            // Count on how many terrors left to be finished
            if (isPursuitSessionActive == false)
            {
                // Should between 1 and 3 because Intro only include 4 terrorists and 3 hostages
                // Frequent use of Common.GetRandomValue "might" be unstable; consider changing it?
                HoldUntilTerrorists_Left(Common.GetRandomValue(1, 3+1));
                return;
            }

            GetArrestedTerrorists();

            // If no more terrorists are active (arrested or killed in the process), end the callout
            if (missionPeds.Count == 0)
            {
                // Get casualties on officers and squad
                GetCasualties();

                // Sum cash gained
                int cashGained = (deadSuspects.Count * MoneyForEachDeadSuspect) + (arrestedSuspects.Count * MoneyForEachArrestedSuspect) +
                    (hostages.Count * RewardForRescuedHostages) - (deadHostages.Count * PenaltyForDeadHostage) - (officers_killed * PenaltyForOfficerCasualties) -
                    (squad_killed * PenaltyForSquadCasualties);

                // Inform player on screen
                Functions.PrintText("Mission complete! Terrorists killed: " + deadSuspects.Count + ", Terrorists arrested: " + arrestedSuspects.Count +
                    " Hostages killed: " + deadHostages.Count + ", Hostages rescued: " + hostages.Count + ", Officer Casualties: " + officers_killed +
                    ", Squad Casualties: " + squad_killed + ", Income for your noble service: $" + cashGained, 30000);

                Functions.AddTextToTextwall("Squad, terrorist threat is neutralized. Mission complete!", LPlayer.LocalPlayer.Username);
                Functions.AddTextToTextwall(Functions.GetStringFromLanguageFile("CALLOUT_SHOOTOUT_END_TW"), Functions.GetStringFromLanguageFile("POLICE_SCANNER_CONTROL"));

                // Add cash
                LPlayer.LocalPlayer.Money += cashGained;

                // Write stats
                WriteStatistics(deadSuspects.Count, arrestedSuspects.Count, deadHostages.Count, hostages.Count, officers_killed, squad_killed, cashGained);

                // Save the progress
                SaveGame();

                Log.Debug("Process: Commands properly assigned", this);

                /*// End everything
                PlaySound(false);
                PlayFinishedMissionSound();
                SetCalloutFinished(true, false, false);*/
                SetCalloutFinished(true, true, false);
                End();
            }
		}

Anyway, this is the very first mod that uses database system, if I need to go off topic for a bit. I got this learning when I practicing C# language from the book and figure out the commands on my own.


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

Actually there's a much much cleaner and simpler method than RegisterCallback, switch(state)..case, ifs etc. It's called Action delegate, that's a variable which stores a pointer to a function. Here's a short example:

Action stage;

public void OnCalloutAccepted()
{
  stage = IsPlayerClose;
}

public void Process()
{
  if(stage != null) stage(); //it calls a function pointed by stage whenever Process() is called, you can also: stage.Invoke()
}

private void IsPlayerClose()
{
  if(Distance(Player, point) < 50f) stage = IsPlayerVeryClose;
}

private void IsPlayerVeryClose()
{
  //code
}

Voila, it's clean, simple and effective.

Share this post


Link to post
Share on other sites
11 hours ago, LtFlash said:

Actually there's a much much cleaner and simpler method than RegisterCallback, switch(state)..case, ifs etc. It's called Action delegate, that's a variable which stores a pointer to a function. Here's a short example:


Action stage;

public void OnCalloutAccepted()
{
  stage = IsPlayerClose;
}

public void Process()
{
  if(stage != null) stage(); //it calls a function pointed by stage whenever Process() is called, you can also: stage.Invoke()
}

private void IsPlayerClose()
{
  if(Distance(Player, point) < 50f) stage = IsPlayerVeryClose;
}

private void IsPlayerVeryClose()
{
  //code
}

Voila, it's clean, simple and effective.

Wow... you know every solutions I have for the project I'm developing. But what's done is done. I'll take your advice if I want to make other LCPDFR API project, @LtFlash. Likewise, if I want to use it in my ongoing project, that means code redesigning. ATM, my method is quite stable to me, because enumerations are processed in the Process function, like the way original Pursuit callout works (LCPDFR mostly processes ongoing event from the Process function).

 

If I have a trouble again while designing this callout, I'll post again in this thread.


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

Anyway, @LtFlash I managed to use the method to bypass the deprecated method to get the blips, but eventually it got an error when coding with Find method. I had to do workaround like this:

                    Blip[] myBlips = Blip.GetAllBlipsOfType(BlipType.Ped);

                    foreach (Blip myBlip in myBlips)
                    {
                        if (myBlip.GetAttachedItem() == myped)
                        {
                            if (myBlip != null) myBlip.Delete();
                        }
                        else continue;
                    }

Is this okay?


“I never go back on my word, that’s my Ninja Way!” – Naruto Uzumaki

Share this post


Link to post
Share on other sites

I 'd apply some cosmetics but generally, it's ok.

Blip[] myBlips = Blip.GetAllBlipsOfType(BlipType.Ped);

foreach (Blip myBlip in myBlips)
{
  if(myBlip == null || !myBlip.Exists()) continue; //always check this first
  
  if (myBlip.GetAttachedItem() == myped) //in case it does not return true when it should, use GetHashCode() for both and compare
  {
      myBlip.Delete();
  }
}

 

Share this post


Link to post
Share on other sites
Guest
This topic is now closed to further replies.

×
×
  • Create New...